Overview

Instructor names and contact information

  • Ruth Isserlin - ruth dot isserlin (at) utoronto (dot) ca
  • Brendan Innes - brendan (dot) innes (at) mail (dot) utoronto (dot) ca
  • Jeff Wong - jvwong (at) gmail (dot) com
  • Gary Bader - gary (dot) bader (at) utoronto (dot) ca

Workshop Description

Cytoscape(www.cytoscape.org) is one of the most popular applications for network analysis and visualization. In this workshop, we will demonstrate new capabilities to integrate Cytoscape into programmatic workflows and pipelines using R. We will begin with an overview of network biology themes and concepts, and then we will translate these into Cytoscape terms for practical applications. The bulk of the workshop will be a hands-on demonstration of accessing and controlling Cytoscape from R to perform a network analysis of tumor expression data.

Workshop prerequisites

  • Basic knowledge of R syntax
  • Basic knowledge of Cytoscape software
  • Familiarity with network biology concepts

Background

Workshop Participation

Participants are required to bring a laptop with Cytoscape, R, and RStudio installed. Installation instructions will be provided in the weeks preceding the workshop. The workshop will consist of a lecture and lab.

R / Bioconductor packages used

  • RCy3
  • gProfileR

Time outline

Activity Time
Introduction 15m
Driving Cytoscape from R 15m
Creating, retrieving and manipulating networks 15m
Summary 10m

Workshop goals and objectives

Learning goals: * Know when and how to use Cytoscape in your research area * Generalize network analysis methods to multiple problem domains * Integrate Cytoscape into your bioinformatics pipelines

Learning objectives: * Programmatic control over Cytoscape from R * Publish, share and export networks

Background

Cytoscape

  • Cytoscape[@cytoscape] is a freely available open-source, cross platform network analysis software.
  • Cytoscape[@cytoscape] can visualize complex networks and help integrate them with any other data type.
  • Cytoscape[@cytoscape] has an active developer and user base with more than 300 community created apps available from the (Cytoscape App Store)[apps.cytoscape.org].
  • Check out some of the tasks you can do with Cytoscape in our online tutorial guide - tutorials.cytoscape.org

Overview of network biology themes and concepts

Why Networks?

Networks are everywhere…

  • Molecular Networks
  • Cell-Cell communication Networks
  • Computer networks
  • Social Networks
  • Internet

Networks are powerful tools…

  • Reduce complexity
  • More efficient than tables
  • Great for data integration
  • Intuitive visualization

Often data in our pipelines are represented as data.frames, tables, matrices, vectors or lists. Sometimes we represent this data as heatmaps, or plots in efforts to summarize the results visually. Network visualization offers an additional method that readily incorporates many different data types and variables into a single picture.

In order to translate your data into a network it is important to define the entities and their relationships. Entities and relationships can be anything. They can be user defined or they can be queried from a database.

Examples of Networks and their associated entities:

  • Protein - Protein interaction network - is a directed or undirected network where nodes in the network are proteins or genes and edges represent how those proteins interact.
  • Gene - gene interaction network - nodes in the network are genes and edges can represent synthetic lethality i.e. two genes have a connection if deleting both of them cause a decrease in fitness.
  • Coexpression network - nodes in the network are genes or proteins and edges represent the degree of co-expression the two genes have. Often the edges are associated with a correlation score (i.e. pearson correlation) and edges are filtered by a defined threshold. If no threshold is specified all genes will be connected to all other genes creating a hairball.
  • Enrichment Map - nodes in the networks are groups of genes from pathways or functions (i.e. genesets) and edges represent pathway crosstalk ( genes in common).
  • Social network - nodes in the network are individuals and edges are some sort of social interaction between two individuals, for example, friends on Facebook, linked in LinkedIN, …
  • Copublication network - a specialization of the social network for research purposes. Nodes in the network are individuals and edges between any two individuals for those who have co-authored a publication together.

Networks as Tools

Networks can be used for two main purposes but often go hand in hand.

Analysis

  • Topological properties - including number of nodes, number of edges, node degree, average clustering coefficients, shortest path lengths, density, and many more. Topological properties can help gain insights into the structure and organization of the resulting biological networks as well as help highlight specific node or regions of the network.
  • Hubs and subnetworks - a hub is generally a highly connected node in a scale-free network. Removal of hubs cause rapid breakdown of the underlying network. Subnetworks are interconnected regions of the network and can be defined by any user defined parameter.
  • Cluster, classify, and diffuse
  • Data integration

Visualization

  • Data overlays
  • Layouts and animation
  • Exploratory analysis
  • Context and interpretation

Translating biological data into Cytoscape using RCy3

Networks offer us a useful way to represent our biological data. But how do we seamlessly translate our data from R into Cytoscape?

There are multiple ways to communicate with Cytoscape programmatically. There are two main complementary portals,cyRest[@cyrest] and Commands, that form the foundation. cyRest transforms Cytoscape in to a REST (Representational State Transfer) enabled service where it essentially listens for events through a predefined port (by default port 1234). The cyRest functionality started as an app add in but has now been incorporated into the main release. Commands, on the other hand, offer a mechanism whereby app developers can expose their functionality to other apps or to user through the command interface. Prior to the implementation of cyRest many of the basic network functions were first available as commands so there is some overlap between the two different methods. @ref(fig:cytoscapeRcy3) shows the different ways you can call Cytoscape.

Set up

In order to create networks in Cytoscape from R you need:

  • RCy3 - a biocondutor package
  • Cytoscape - Download and install Cytoscape 3.6.1. or higher. Java 9 in not supported. Please make sure that Java 8 is installed.
    • Install additional cytoscape apps that will be used in this workshop. If using cytoscape 3.6.1 or older the apps need to manually installed through the app manager in Cytoscape or through your web browser. (click on the method to see detailed instructions)
      • Functional Enrichment Collection -a collection of apps to retrieve networks and pathways, integrate and explore the data, perform functional enrichment analysis, and interpret and display your results.
      • EnrichmentMap Pipeline Collection - a collection of apps including EnrichmentMap[@enrichmentmap], AutoAnnotate[@autoannotate], WordCloud[@wordcloud] and clusterMaker2[@clustermaker] used to visualize and analysis enrichment results.

If you are using Cytoscape 3.7 or higher then apps can be installed directly from R.

Make sure that Cytoscape is running

Getting started

Confirm that Cytoscape is installed and opened

Browse available functions, commands and arguments

Depending on what apps you have installed there is different functionality available.

To see all the functions available in RCy3 package

Open swagger docs for live instances of CyREST API. The CyREST API list all the functions available in a base distribution of cytoscape. The below command will launch the swagger documentation in a web browser. Functions are clustered into categories. Expanding individual categories will show all the option available. Further expanding an individual command will show detailed documentation for the function, input, outputs and allow you to try and run the function. Running the function will show the url used for the query and all returned responses.

As mentioned above, there are two ways to interact with Cytoscape, through the Cyrest API or commands. To see the available commands in swagger similar to the Cyrest API.

To get information about an individual command from the R environment you can also use the commandsHelp function. Simply specify what command you would like to get information on by adding its name to the command. For example “commandsHelp(”help string“)”

Example Data Set

We downloaded gene expression data from the Ovarian Serous Cystadenocarcinoma project of The Cancer Genome Atlas (TCGA)[@TCGA], http://cancergenome.nih.gov via the Genomic Data Commons (GDC) portal[@GDC] on 2017-06-14 using TCGABiolinks R package[@TCGABiolinks]. The data includes 300 samples available as RNA-seq data, with reads mapped to a reference genome using MapSplice[@MapSplice] and read counts per transcript determined using the RSEM method[@RSEM]. RNA-seq data are labeled as ‘RNA-Seq V2’, see details at: https://wiki.nci.nih.gov/display/TCGA/RNASeq+Version+2). The RNA-SeqV2 data consists of raw counts similar to regular RNA-seq but RSEM (RNA-Seq by Expectation Maximization) data can be used with the edgeR method. The expression dataset of 300 tumours, with 79 classified as Immunoreactive, 72 classified as Mesenchymal, 69 classified as Differentiated, and 80 classified as Proliferative samples(class definitions were obtained from Verhaak et al.[@OV] Supplementary Table 1, third column). RNA-seq read counts were converted to CPM values and genes with CPM > 1 in at least 50 of the samples are retained for further study (50 is the minimal sample size in the classes). The data was normalized and differential expression was calculated for each cancer class relative to the rest of the samples.

There are two data files: 1. Expression matrix - containing the normalized expression for each gene across all 300 samples. 1. Gene ranks - containing the p-values, FDR and foldchange values for the 4 comparisons (mesenchymal vs rest, differential vs rest, proliferative vs rest and immunoreactive vs rest)

The following commands will create a new directory in your current directory, and download the data files to it.

Now we can read the downloaded files into R:

Finding Network Data

How do I represent my data as a network?

Unfortunately, there is not a simple answer. It depends on your biological question!

Example use cases:

  1. Omics data - I have a fill in the blank (microarray, RNASeq, Proteomics, ATACseq, MicroRNA, GWAS …) dataset. I have normalized and scored my data. How do I overlay my data on existing interaction data?
  2. Coexpression data - I have a dataset that represents relationships. How do I represent it as a network.

Use Case 2 - Which genes have similar expression.

Instead of querying existing resources look for correlations in your own dataset to find out which genes have similar expression. There are many tools that can analyze your data for correlation. A popular tool is Weighted Gene Correlation Network Analysis (WGCNA)[@wgcna] which takes expression data and calculates functional modules. As a simple example we can transform our expression dataset into a correlation matrix.

Using the Cytoscape App, aMatReader[@amatreader], we transform our adjacency matrix into an interaction network. First we filter the correlation matrix to contain only the strongest connections (for example, only correlations greater than 0.9).

Use the CyRest call to access the aMatReader functionality.

Modify the visualization to see where each genes is predominantly expressed. Look at the 4 different p-values associated with each gene and color the nodes with the type associated with the lowest FDR.

Load in the scoring data. Specify the cancer type where the genes has the lowest FDR value.

Map the new node attribute and the all the gene scores to the network.

Create a color mapping for the different cancer types.

cluster the Network

Perform pathway Enrichment on one of the clusters using g:Profiler[@gprofiler]. g:Profiler is an online functional enrichment web service that will take your gene list and return the set of enriched pathways. For automated analysis g:Profiler has created an R library to interact with it directly from R instead of using the web page.

Create a function to call g:Profiler and convert the returned results into a generic enrichment map input file.

Run g:Profiler. g:Profiler will return a set of pathways and functions that are found to be enriched in our query set of genes.

Create an enrichment map with the returned g:Profiler results. An enrichment map is a different sort of network. Instead of nodes representing genes, nodes represent pathways or functions. Edges between these pathways or functions represent shared genes or pathway crosstalk. An enrichment map is a way to visualize your enrichment results to help reduce redundancy and uncover main themes. Pathways can also be explored in detail using the features available through the App in Cytoscape.

Export image of resulting Enrichment map.

Annotate the Enrichment map to get the general themes that are found in the enrichment results of cluster 1

Export image of resulting Annotated Enrichment map.

Dense networks small or large never look like network figures we so often see in journals. A lot of manual tweaking, reorganization and optimization is involved in getting that perfect figure ready network. The above network is what the network starts as. The below figure is what it can look like after a few minutes of manual reorganiazation. (individual clusters were selected from the auto annotate panel and separated from other clusters)

LS0tCnRpdGxlOiAiQ3l0b3NjYXBlIGF1dG9tYXRpb24gaW4gUiB1c2luZyBSY3kzIgphdXRob3I6ICJieSBSdXRoIElzc2VybGluIgpwYWNrYWdlOiBSQ3kzCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6ICJub25lIgojICBwZGZfZG9jdW1lbnQ6CiMgICAgdG9jOiB0cnVlICAKLS0tCmBgYHtyLCBlY2hvID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBldmFsPUZBTFNFCikKYGBgCgpgYGB7ciBsaWIsIGVjaG89RkFMU0UsIHJlc3VsdHM9ImhpZGUiLCBjYWNoZT1GQUxTRX0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKCWxpYnJhcnkoRW5yaWNobWVudEJyb3dzZXIpCglsaWJyYXJ5KFJDeTMpCglsaWJyYXJ5KFJDb2xvckJyZXdlcikKCWxpYnJhcnkoZ1Byb2ZpbGVSKQp9KQpgYGAKCiMgT3ZlcnZpZXcKCiMjIyBJbnN0cnVjdG9yIG5hbWVzIGFuZCBjb250YWN0IGluZm9ybWF0aW9uCgoqIFJ1dGggSXNzZXJsaW4gLSBydXRoIGRvdCBpc3NlcmxpbiAoYXQpIHV0b3JvbnRvIChkb3QpIGNhCiogQnJlbmRhbiBJbm5lcyAtIGJyZW5kYW4gKGRvdCkgaW5uZXMgKGF0KSBtYWlsIChkb3QpIHV0b3JvbnRvIChkb3QpIGNhCiogSmVmZiBXb25nIC0ganZ3b25nIChhdCkgZ21haWwgKGRvdCkgY29tIAoqIEdhcnkgQmFkZXIgLSBnYXJ5IChkb3QpIGJhZGVyIChhdCkgdXRvcm9udG8gKGRvdCkgY2EKCiMjIyBXb3Jrc2hvcCBEZXNjcmlwdGlvbgoKQ3l0b3NjYXBlKHd3dy5jeXRvc2NhcGUub3JnKSBpcyBvbmUgb2YgdGhlIG1vc3QgcG9wdWxhciBhcHBsaWNhdGlvbnMgZm9yIG5ldHdvcmsgYW5hbHlzaXMgYW5kIHZpc3VhbGl6YXRpb24uIEluIHRoaXMgd29ya3Nob3AsIHdlIHdpbGwgZGVtb25zdHJhdGUgbmV3IGNhcGFiaWxpdGllcyB0byBpbnRlZ3JhdGUgQ3l0b3NjYXBlIGludG8gcHJvZ3JhbW1hdGljIHdvcmtmbG93cyBhbmQgcGlwZWxpbmVzIHVzaW5nIFIuIFdlIHdpbGwgYmVnaW4gd2l0aCBhbiBvdmVydmlldyBvZiBuZXR3b3JrIGJpb2xvZ3kgdGhlbWVzIGFuZCBjb25jZXB0cywgYW5kIHRoZW4gd2Ugd2lsbCB0cmFuc2xhdGUgdGhlc2UgaW50byBDeXRvc2NhcGUgdGVybXMgZm9yIHByYWN0aWNhbCBhcHBsaWNhdGlvbnMuIFRoZSBidWxrIG9mIHRoZSB3b3Jrc2hvcCB3aWxsIGJlIGEgaGFuZHMtb24gZGVtb25zdHJhdGlvbiBvZiBhY2Nlc3NpbmcgYW5kIGNvbnRyb2xsaW5nIEN5dG9zY2FwZSBmcm9tIFIgdG8gcGVyZm9ybSBhIG5ldHdvcmsgYW5hbHlzaXMgb2YgdHVtb3IgZXhwcmVzc2lvbiBkYXRhLgoKIyMjIFdvcmtzaG9wIHByZXJlcXVpc2l0ZXMKKiBCYXNpYyBrbm93bGVkZ2Ugb2YgUiBzeW50YXgKKiBCYXNpYyBrbm93bGVkZ2Ugb2YgQ3l0b3NjYXBlIHNvZnR3YXJlCiogRmFtaWxpYXJpdHkgd2l0aCBuZXR3b3JrIGJpb2xvZ3kgY29uY2VwdHMKCiMjIyBCYWNrZ3JvdW5kCiog4oCcSG93IHRvIHZpc3VhbGx5IGludGVycHJldCBiaW9sb2dpY2FsIGRhdGEgdXNpbmcgbmV0d29ya3Mu4oCdIE1lcmljbyBELCBHZmVsbGVyIEQsIEJhZGVyIEdELiBOYXR1cmUgQmlvdGVjaG5vbG9neSAyMDA5IE9jdCAyNywgOTIxLTkyNCAtIGh0dHA6Ly9iYWRlcmxhYi5vcmcvUHVibGljYXRpb25zP2FjdGlvbj1BdHRhY2hGaWxlJmRvPXZpZXcmdGFyZ2V0PTIwMDlfTWVyaWNvX1ByaW1lcl9OYXRCaW90ZWNoX09jdC5wZGYKKiDigJxDeVJFU1Q6IFR1cmJvY2hhcmdpbmcgQ3l0b3NjYXBlIEFjY2VzcyBmb3IgRXh0ZXJuYWwgVG9vbHMgdmlhIGEgUkVTVGZ1bCBBUEnigJ0uIEtlaWljaGlybyBPbm8sIFRhbmphIE11ZXR6ZSwgR2VvcmdpIEtvbGlzaG92c2tpLCBQYXVsIFNoYW5ub24sIEJhcnJ5IERlbWNoYWsuRjEwMDBSZXMuIDIwMTUgQXVnIDU7NDo0NzguIC0gaHR0cHM6Ly9mMTAwMHJlc2VhcmNoLmNvbS9hcnRpY2xlcy80LTQ3OC92MQoKIyMjIFdvcmtzaG9wIFBhcnRpY2lwYXRpb24KUGFydGljaXBhbnRzIGFyZSByZXF1aXJlZCB0byBicmluZyBhIGxhcHRvcCB3aXRoIEN5dG9zY2FwZSwgUiwgYW5kIFJTdHVkaW8gaW5zdGFsbGVkLiAgSW5zdGFsbGF0aW9uIGluc3RydWN0aW9ucyB3aWxsIGJlIHByb3ZpZGVkIGluIHRoZSB3ZWVrcyBwcmVjZWRpbmcgdGhlIHdvcmtzaG9wLiAgVGhlIHdvcmtzaG9wIHdpbGwgY29uc2lzdCBvZiBhIGxlY3R1cmUgYW5kIGxhYi4KCiMjIyBSIC8gQmlvY29uZHVjdG9yIHBhY2thZ2VzIHVzZWQKKiBSQ3kzCiogZ1Byb2ZpbGVSCgojIyMgVGltZSBvdXRsaW5lCgp8IEFjdGl2aXR5ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBUaW1lIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS18CnwgSW50cm9kdWN0aW9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDE1bSAgfAp8IERyaXZpbmcgQ3l0b3NjYXBlIGZyb20gUiAgICAgICAgICAgICAgICAgICAgICAgfCAxNW0gIHwKfCBDcmVhdGluZywgcmV0cmlldmluZyBhbmQgbWFuaXB1bGF0aW5nIG5ldHdvcmtzIHwgMTVtICB8CnwgU3VtbWFyeSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IDEwbSAgfAoKCiMjIyBXb3Jrc2hvcCBnb2FscyBhbmQgb2JqZWN0aXZlcwoKTGVhcm5pbmcgZ29hbHM6CiogS25vdyB3aGVuIGFuZCBob3cgdG8gdXNlIEN5dG9zY2FwZSBpbiB5b3VyIHJlc2VhcmNoIGFyZWEKKiBHZW5lcmFsaXplIG5ldHdvcmsgYW5hbHlzaXMgbWV0aG9kcyB0byBtdWx0aXBsZSBwcm9ibGVtIGRvbWFpbnMKKiBJbnRlZ3JhdGUgQ3l0b3NjYXBlIGludG8geW91ciBiaW9pbmZvcm1hdGljcyBwaXBlbGluZXMKCkxlYXJuaW5nIG9iamVjdGl2ZXM6CiogUHJvZ3JhbW1hdGljIGNvbnRyb2wgb3ZlciBDeXRvc2NhcGUgZnJvbSBSCiogUHVibGlzaCwgc2hhcmUgYW5kIGV4cG9ydCBuZXR3b3JrcwoKIyBCYWNrZ3JvdW5kCiMjIEN5dG9zY2FwZQo8ZGl2IGlkPSJsZWZ0X2xvZ28iPiFbQ3l0b3NjYXBlIEFwcHNdKC4vYmlvYzIwMThfUmN5M19pbnRyby8yMzBfSXNzZXJsaW5fUkN5M19pbnRyby9pbWFnZXMvY3kzbG9nb09yYW5nZS5wbmcpe3dpZHRoPTEwMHB4fTwvZGl2PgoKICAqIFtDeXRvc2NhcGVdKHd3dy5jeXRvc2NhcGUub3JnKVtAY3l0b3NjYXBlXSBpcyBhIGZyZWVseSBhdmFpbGFibGUgb3Blbi1zb3VyY2UsIGNyb3NzIHBsYXRmb3JtIG5ldHdvcmsgYW5hbHlzaXMgc29mdHdhcmUuICAKICAqIFtDeXRvc2NhcGVdKHd3dy5jeXRvc2NhcGUub3JnKVtAY3l0b3NjYXBlXSBjYW4gdmlzdWFsaXplIGNvbXBsZXggbmV0d29ya3MgYW5kIGhlbHAgaW50ZWdyYXRlIHRoZW0gd2l0aCBhbnkgb3RoZXIgZGF0YSB0eXBlLiAgCiAgKiBbQ3l0b3NjYXBlXSh3d3cuY3l0b3NjYXBlLm9yZylbQGN5dG9zY2FwZV0gaGFzIGFuIGFjdGl2ZSBkZXZlbG9wZXIgYW5kIHVzZXIgYmFzZSB3aXRoIG1vcmUgdGhhbiAqKjMwMCoqIGNvbW11bml0eSBjcmVhdGVkIGFwcHMgYXZhaWxhYmxlIGZyb20gdGhlIChDeXRvc2NhcGUgQXBwIFN0b3JlKVthcHBzLmN5dG9zY2FwZS5vcmddLgogICogQ2hlY2sgb3V0IHNvbWUgb2YgdGhlIHRhc2tzIHlvdSBjYW4gZG8gd2l0aCBDeXRvc2NhcGUgaW4gb3VyIG9ubGluZSB0dXRvcmlhbCBndWlkZSAtIHR1dG9yaWFscy5jeXRvc2NhcGUub3JnCgojIyBPdmVydmlldyBvZiBuZXR3b3JrIGJpb2xvZ3kgdGhlbWVzIGFuZCBjb25jZXB0cwojIyMgV2h5IE5ldHdvcmtzPwpOZXR3b3JrcyBhcmUgZXZlcnl3aGVyZS4uLgoKICAqIE1vbGVjdWxhciBOZXR3b3JrcwogICogQ2VsbC1DZWxsIGNvbW11bmljYXRpb24gTmV0d29ya3MKICAqIENvbXB1dGVyIG5ldHdvcmtzCiAgKiBTb2NpYWwgTmV0d29ya3MKICAqIEludGVybmV0CiAgCk5ldHdvcmtzIGFyZSBwb3dlcmZ1bCB0b29scy4uLgoKICAqIFJlZHVjZSBjb21wbGV4aXR5CiAgKiBNb3JlIGVmZmljaWVudCB0aGFuIHRhYmxlcwogICogR3JlYXQgZm9yIGRhdGEgaW50ZWdyYXRpb24KICAqIEludHVpdGl2ZSB2aXN1YWxpemF0aW9uCiAgCk9mdGVuIGRhdGEgaW4gb3VyIHBpcGVsaW5lcyBhcmUgcmVwcmVzZW50ZWQgYXMgZGF0YS5mcmFtZXMsIHRhYmxlcywgbWF0cmljZXMsIHZlY3RvcnMgb3IgbGlzdHMuICBTb21ldGltZXMgd2UgcmVwcmVzZW50IHRoaXMgZGF0YSBhcyBoZWF0bWFwcywgb3IgcGxvdHMgaW4gZWZmb3J0cyB0byBzdW1tYXJpemUgdGhlIHJlc3VsdHMgdmlzdWFsbHkuICBOZXR3b3JrIHZpc3VhbGl6YXRpb24gb2ZmZXJzIGFuIGFkZGl0aW9uYWwgbWV0aG9kIHRoYXQgcmVhZGlseSBpbmNvcnBvcmF0ZXMgbWFueSBkaWZmZXJlbnQgZGF0YSB0eXBlcyBhbmQgdmFyaWFibGVzIGludG8gYSBzaW5nbGUgcGljdHVyZS4gCgo8Y2VudGVyPgohW10oaHR0cHM6Ly9jeXRvc2NhcGUuZ2l0aHViLmlvL2N5dG9zY2FwZS1hdXRvbWF0aW9uL2Zvci1zY3JpcHRlcnMvUi9ub3RlYm9va3MvYmlvYzIwMThfUmN5M19pbnRyby8yMzBfSXNzZXJsaW5fUkN5M19pbnRyby9pbWFnZXMvdGFibGVzMm5ldHdvcmtzLnBuZykKPC9jZW50ZXI+CgpJbiBvcmRlciB0byB0cmFuc2xhdGUgeW91ciBkYXRhIGludG8gYSBuZXR3b3JrIGl0IGlzIGltcG9ydGFudCB0byBkZWZpbmUgdGhlIGVudGl0aWVzIGFuZCB0aGVpciByZWxhdGlvbnNoaXBzLiAgRW50aXRpZXMgYW5kIHJlbGF0aW9uc2hpcHMgY2FuIGJlIGFueXRoaW5nLiBUaGV5IGNhbiBiZSB1c2VyIGRlZmluZWQgb3IgdGhleSBjYW4gYmUgcXVlcmllZCBmcm9tIGEgZGF0YWJhc2UuCgpFeGFtcGxlcyBvZiBOZXR3b3JrcyBhbmQgdGhlaXIgYXNzb2NpYXRlZCBlbnRpdGllczoKCiAgKiAqKlByb3RlaW4gLSBQcm90ZWluIGludGVyYWN0aW9uIG5ldHdvcmsqKiAtIGlzIGEgZGlyZWN0ZWQgb3IgdW5kaXJlY3RlZCBuZXR3b3JrIHdoZXJlIG5vZGVzIGluIHRoZSBuZXR3b3JrIGFyZSBwcm90ZWlucyBvciBnZW5lcyBhbmQgZWRnZXMgcmVwcmVzZW50IGhvdyB0aG9zZSBwcm90ZWlucyBpbnRlcmFjdC4gICAKICAqICoqR2VuZSAtIGdlbmUgaW50ZXJhY3Rpb24gbmV0d29yayoqIC0gbm9kZXMgaW4gdGhlIG5ldHdvcmsgYXJlIGdlbmVzIGFuZCBlZGdlcyBjYW4gcmVwcmVzZW50IHN5bnRoZXRpYyBsZXRoYWxpdHkgaS5lLiB0d28gZ2VuZXMgaGF2ZSBhIGNvbm5lY3Rpb24gaWYgZGVsZXRpbmcgYm90aCBvZiB0aGVtIGNhdXNlIGEgZGVjcmVhc2UgaW4gZml0bmVzcy4gIAogICogKipDb2V4cHJlc3Npb24gbmV0d29yayoqIC0gbm9kZXMgaW4gdGhlIG5ldHdvcmsgYXJlIGdlbmVzIG9yIHByb3RlaW5zIGFuZCBlZGdlcyByZXByZXNlbnQgdGhlIGRlZ3JlZSBvZiBjby1leHByZXNzaW9uIHRoZSB0d28gZ2VuZXMgaGF2ZS4gIE9mdGVuIHRoZSBlZGdlcyBhcmUgYXNzb2NpYXRlZCB3aXRoIGEgY29ycmVsYXRpb24gc2NvcmUgKGkuZS4gcGVhcnNvbiBjb3JyZWxhdGlvbikgYW5kIGVkZ2VzIGFyZSBmaWx0ZXJlZCBieSBhIGRlZmluZWQgdGhyZXNob2xkLiAgSWYgbm8gdGhyZXNob2xkIGlzIHNwZWNpZmllZCBhbGwgZ2VuZXMgd2lsbCBiZSBjb25uZWN0ZWQgdG8gYWxsIG90aGVyIGdlbmVzIGNyZWF0aW5nIGEgaGFpcmJhbGwuCiAgKiAqKkVucmljaG1lbnQgTWFwKiogLSBub2RlcyBpbiB0aGUgbmV0d29ya3MgYXJlIGdyb3VwcyBvZiBnZW5lcyBmcm9tIHBhdGh3YXlzIG9yIGZ1bmN0aW9ucyAoaS5lLiBnZW5lc2V0cykgYW5kIGVkZ2VzIHJlcHJlc2VudCBwYXRod2F5IGNyb3NzdGFsayAoIGdlbmVzIGluIGNvbW1vbikuCiAgKiAqKlNvY2lhbCBuZXR3b3JrKiogLSAgbm9kZXMgaW4gdGhlIG5ldHdvcmsgYXJlIGluZGl2aWR1YWxzIGFuZCBlZGdlcyBhcmUgc29tZSBzb3J0IG9mIHNvY2lhbCBpbnRlcmFjdGlvbiBiZXR3ZWVuIHR3byBpbmRpdmlkdWFscywgZm9yIGV4YW1wbGUsIGZyaWVuZHMgb24gRmFjZWJvb2ssIGxpbmtlZCBpbiBMaW5rZWRJTiwgLi4uCiAgKiAqKkNvcHVibGljYXRpb24gbmV0d29yayoqIC0gYSBzcGVjaWFsaXphdGlvbiBvZiB0aGUgc29jaWFsIG5ldHdvcmsgZm9yIHJlc2VhcmNoIHB1cnBvc2VzLiBOb2RlcyBpbiB0aGUgbmV0d29yayBhcmUgaW5kaXZpZHVhbHMgYW5kIGVkZ2VzIGJldHdlZW4gYW55IHR3byBpbmRpdmlkdWFscyBmb3IgdGhvc2Ugd2hvIGhhdmUgY28tYXV0aG9yZWQgYSBwdWJsaWNhdGlvbiB0b2dldGhlci4KICAKCiMjIE5ldHdvcmtzIGFzIFRvb2xzCk5ldHdvcmtzIGNhbiBiZSB1c2VkIGZvciB0d28gbWFpbiBwdXJwb3NlcyBidXQgb2Z0ZW4gZ28gaGFuZCBpbiBoYW5kLiAgCgoqKkFuYWx5c2lzKioKCiAqIFRvcG9sb2dpY2FsIHByb3BlcnRpZXMgLSBpbmNsdWRpbmcgbnVtYmVyIG9mIG5vZGVzLCBudW1iZXIgb2YgZWRnZXMsIG5vZGUgZGVncmVlLCBhdmVyYWdlIGNsdXN0ZXJpbmcgY29lZmZpY2llbnRzLCBzaG9ydGVzdCBwYXRoIGxlbmd0aHMsIGRlbnNpdHksIGFuZCBtYW55IG1vcmUuICBUb3BvbG9naWNhbCBwcm9wZXJ0aWVzIGNhbiBoZWxwIGdhaW4gaW5zaWdodHMgaW50byB0aGUgc3RydWN0dXJlIGFuZCBvcmdhbml6YXRpb24gb2YgdGhlIHJlc3VsdGluZyBiaW9sb2dpY2FsIG5ldHdvcmtzIGFzIHdlbGwgYXMgaGVscCBoaWdobGlnaHQgc3BlY2lmaWMgbm9kZSBvciByZWdpb25zIG9mIHRoZSBuZXR3b3JrLiAgCiAqIEh1YnMgYW5kIHN1Ym5ldHdvcmtzIC0gYSBodWIgaXMgZ2VuZXJhbGx5IGEgaGlnaGx5IGNvbm5lY3RlZCBub2RlIGluIGEgc2NhbGUtZnJlZSBuZXR3b3JrLiAgUmVtb3ZhbCBvZiBodWJzIGNhdXNlIHJhcGlkIGJyZWFrZG93biBvZiB0aGUgdW5kZXJseWluZyBuZXR3b3JrLiAgU3VibmV0d29ya3MgYXJlIGludGVyY29ubmVjdGVkIHJlZ2lvbnMgb2YgdGhlIG5ldHdvcmsgYW5kIGNhbiBiZSBkZWZpbmVkIGJ5IGFueSB1c2VyIGRlZmluZWQgcGFyYW1ldGVyLiAgCiAqIENsdXN0ZXIsIGNsYXNzaWZ5LCBhbmQgZGlmZnVzZSAgCiAqIERhdGEgaW50ZWdyYXRpb24KIAoqKlZpc3VhbGl6YXRpb24qKgoKICogRGF0YSBvdmVybGF5cwogKiBMYXlvdXRzIGFuZCBhbmltYXRpb24KICogRXhwbG9yYXRvcnkgYW5hbHlzaXMKICogQ29udGV4dCBhbmQgaW50ZXJwcmV0YXRpb24KIAojIFRyYW5zbGF0aW5nIGJpb2xvZ2ljYWwgZGF0YSBpbnRvIEN5dG9zY2FwZSB1c2luZyBSQ3kzCgpOZXR3b3JrcyBvZmZlciB1cyBhIHVzZWZ1bCB3YXkgdG8gcmVwcmVzZW50IG91ciBiaW9sb2dpY2FsIGRhdGEuICBCdXQgaG93IGRvIHdlIHNlYW1sZXNzbHkgdHJhbnNsYXRlIG91ciBkYXRhIGZyb20gUiBpbnRvIEN5dG9zY2FwZT8KCjxjZW50ZXI+CiFbXShodHRwczovL2N5dG9zY2FwZS5naXRodWIuaW8vY3l0b3NjYXBlLWF1dG9tYXRpb24vZm9yLXNjcmlwdGVycy9SL25vdGVib29rcy9iaW9jMjAxOF9SY3kzX2ludHJvLzIzMF9Jc3Nlcmxpbl9SQ3kzX2ludHJvL2ltYWdlcy9DeXRvc2NhcGVBdXRvbWF0aW9uXzMucG5nKQo8L2NlbnRlcj4KClRoZXJlIGFyZSBtdWx0aXBsZSB3YXlzIHRvIGNvbW11bmljYXRlIHdpdGggQ3l0b3NjYXBlIHByb2dyYW1tYXRpY2FsbHkuICBUaGVyZSBhcmUgdHdvIG1haW4gY29tcGxlbWVudGFyeSBwb3J0YWxzLCoqY3lSZXN0KipbQGN5cmVzdF0gYW5kICoqQ29tbWFuZHMqKiwgdGhhdCBmb3JtIHRoZSBmb3VuZGF0aW9uLiAgY3lSZXN0IHRyYW5zZm9ybXMgQ3l0b3NjYXBlIGluIHRvIGEgUkVTVCAoUmVwcmVzZW50YXRpb25hbCBTdGF0ZSBUcmFuc2ZlcikgZW5hYmxlZCBzZXJ2aWNlIHdoZXJlIGl0IGVzc2VudGlhbGx5IGxpc3RlbnMgZm9yIGV2ZW50cyB0aHJvdWdoIGEgcHJlZGVmaW5lZCBwb3J0IChieSBkZWZhdWx0IHBvcnQgMTIzNCkuICBUaGUgY3lSZXN0IGZ1bmN0aW9uYWxpdHkgc3RhcnRlZCBhcyBhbiBhcHAgYWRkIGluIGJ1dCBoYXMgbm93IGJlZW4gaW5jb3Jwb3JhdGVkIGludG8gdGhlIG1haW4gcmVsZWFzZS4gQ29tbWFuZHMsIG9uIHRoZSBvdGhlciBoYW5kLCBvZmZlciBhIG1lY2hhbmlzbSB3aGVyZWJ5IGFwcCBkZXZlbG9wZXJzIGNhbiBleHBvc2UgdGhlaXIgZnVuY3Rpb25hbGl0eSB0byBvdGhlciBhcHBzIG9yIHRvIHVzZXIgdGhyb3VnaCB0aGUgY29tbWFuZCBpbnRlcmZhY2UuICBQcmlvciB0byB0aGUgaW1wbGVtZW50YXRpb24gb2YgY3lSZXN0IG1hbnkgb2YgdGhlIGJhc2ljIG5ldHdvcmsgZnVuY3Rpb25zIHdlcmUgZmlyc3QgYXZhaWxhYmxlIGFzIGNvbW1hbmRzIHNvIHRoZXJlIGlzIHNvbWUgb3ZlcmxhcCBiZXR3ZWVuIHRoZSB0d28gZGlmZmVyZW50IG1ldGhvZHMuICBcQHJlZihmaWc6Y3l0b3NjYXBlUmN5Mykgc2hvd3MgdGhlIGRpZmZlcmVudCB3YXlzIHlvdSBjYW4gY2FsbCBDeXRvc2NhcGUuCgojIyBTZXQgdXAKYGBge3IgaW5jbHVkZT1GQUxTRX0KZXZhbCA9IEZBTFNFCmBgYAoKCkluIG9yZGVyIHRvIGNyZWF0ZSBuZXR3b3JrcyBpbiBDeXRvc2NhcGUgZnJvbSBSIHlvdSBuZWVkOgoKICogKipSQ3kzKiogLSBhIGJpb2NvbmR1dG9yIHBhY2thZ2UKIApgYGB7ciBpbnN0YWxsUmN5M30KaWYoISJSQ3kzIiAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpKXsKICAgIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikKICAgIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJSQ3kzIikKfQpsaWJyYXJ5KFJDeTMpCmBgYAoKICogKipDeXRvc2NhcGUqKiAtIERvd25sb2FkIGFuZCBpbnN0YWxsIFtDeXRvc2NhcGUgMy42LjEuXShjeXRvc2NhcGUub3JnL2Rvd25sb2FkLnBocCkgb3IgaGlnaGVyLiAgSmF2YSA5IGluIG5vdCBzdXBwb3J0ZWQuICBQbGVhc2UgbWFrZSBzdXJlIHRoYXQgSmF2YSA4IGlzIGluc3RhbGxlZC4KICAgKiBJbnN0YWxsIGFkZGl0aW9uYWwgY3l0b3NjYXBlIGFwcHMgdGhhdCB3aWxsIGJlIHVzZWQgaW4gdGhpcyB3b3Jrc2hvcC4gIElmIHVzaW5nIGN5dG9zY2FwZSAzLjYuMSBvciBvbGRlciB0aGUgYXBwcyBuZWVkIHRvIG1hbnVhbGx5IGluc3RhbGxlZCB0aHJvdWdoIHRoZSBbYXBwIG1hbmFnZXJdKGh0dHA6Ly9tYW51YWwuY3l0b3NjYXBlLm9yZy9lbi9sYXRlc3QvQXBwX01hbmFnZXIuaHRtbCNpbnN0YWxsaW5nLWFwcHMpIGluIEN5dG9zY2FwZSBvciB0aHJvdWdoIHlvdXIgW3dlYiBicm93c2VyXShodHRwczovL2FwcHMuY3l0b3NjYXBlLm9yZy9oZWxwL2dldHN0YXJ0ZWRfYXBwX2luc3RhbGwpLiAgKGNsaWNrIG9uIHRoZSBtZXRob2QgdG8gc2VlIGRldGFpbGVkIGluc3RydWN0aW9ucykKICAgICAqIFtGdW5jdGlvbmFsIEVucmljaG1lbnQgQ29sbGVjdGlvbl0oaHR0cDovL2FwcHMuY3l0b3NjYXBlLm9yZy9hcHBzL2Z1bmN0aW9uYWxlbnJpY2htZW50Y29sbGVjdGlvbikgLWEgY29sbGVjdGlvbiBvZiBhcHBzIHRvIHJldHJpZXZlIG5ldHdvcmtzIGFuZCBwYXRod2F5cywgaW50ZWdyYXRlIGFuZCBleHBsb3JlIHRoZSBkYXRhLCBwZXJmb3JtIGZ1bmN0aW9uYWwgZW5yaWNobWVudCBhbmFseXNpcywgYW5kIGludGVycHJldCBhbmQgZGlzcGxheSB5b3VyIHJlc3VsdHMuCiAgICAgKiBbRW5yaWNobWVudE1hcCBQaXBlbGluZSBDb2xsZWN0aW9uXShodHRwOi8vYXBwcy5jeXRvc2NhcGUub3JnL2FwcHMvZW5yaWNobWVudG1hcHBpcGVsaW5lY29sbGVjdGlvbikgLSBhIGNvbGxlY3Rpb24gb2YgYXBwcyBpbmNsdWRpbmcgRW5yaWNobWVudE1hcFtAZW5yaWNobWVudG1hcF0sIEF1dG9Bbm5vdGF0ZVtAYXV0b2Fubm90YXRlXSwgV29yZENsb3VkW0B3b3JkY2xvdWRdIGFuZCBjbHVzdGVyTWFrZXIyW0BjbHVzdGVybWFrZXJdIHVzZWQgdG8gdmlzdWFsaXplIGFuZCBhbmFseXNpcyBlbnJpY2htZW50IHJlc3VsdHMuCgpJZiB5b3UgYXJlIHVzaW5nIEN5dG9zY2FwZSAzLjcgb3IgaGlnaGVyIHRoZW4gYXBwcyBjYW4gYmUgaW5zdGFsbGVkIGRpcmVjdGx5IGZyb20gUi4KCmBgYHtyfQojYXZhaWxhYmxlIGluIEN5dG9zY2FwZSAzLjcuMCBhbmQgYWJvdmUKaW5zdGFsbEFwcCgnU1RSSU5HYXBwJykgIAppbnN0YWxsQXBwKCdhTWF0UmVhZGVyJykKaW5zdGFsbEFwcCgnY2x1c3Rlck1ha2VyMicpCmBgYAogICAKKipNYWtlIHN1cmUgdGhhdCBDeXRvc2NhcGUgaXMgcnVubmluZyoqCmBgYHtyIGV2YWw9RkFMU0V9CiBjeXRvc2NhcGVQaW5nICgpCmBgYAoKIyMgR2V0dGluZyBzdGFydGVkCiMjIyBDb25maXJtIHRoYXQgQ3l0b3NjYXBlIGlzIGluc3RhbGxlZCBhbmQgb3BlbmVkCmBgYHtyIGV2YWw9RkFMU0V9CiBjeXRvc2NhcGVWZXJzaW9uSW5mbyAoKQpgYGAKCiMjIyBCcm93c2UgYXZhaWxhYmxlIGZ1bmN0aW9ucywgY29tbWFuZHMgYW5kIGFyZ3VtZW50cwpEZXBlbmRpbmcgb24gd2hhdCBhcHBzIHlvdSBoYXZlIGluc3RhbGxlZCB0aGVyZSBpcyBkaWZmZXJlbnQgZnVuY3Rpb25hbGl0eSBhdmFpbGFibGUuICAKClRvIHNlZSBhbGwgdGhlIGZ1bmN0aW9ucyBhdmFpbGFibGUgaW4gUkN5MyBwYWNrYWdlCmBgYHtyfQpoZWxwKHBhY2thZ2U9UkN5MykKYGBgCgpPcGVuIHN3YWdnZXIgZG9jcyBmb3IgbGl2ZSBpbnN0YW5jZXMgb2YgQ3lSRVNUIEFQSS4gIFRoZSBDeVJFU1QgIEFQSSBsaXN0IGFsbCB0aGUgZnVuY3Rpb25zIGF2YWlsYWJsZSBpbiBhIGJhc2UgZGlzdHJpYnV0aW9uIG9mIGN5dG9zY2FwZS4gIFRoZSBiZWxvdyBjb21tYW5kIHdpbGwgbGF1bmNoIHRoZSBzd2FnZ2VyIGRvY3VtZW50YXRpb24gaW4gYSB3ZWIgYnJvd3Nlci4gIEZ1bmN0aW9ucyBhcmUgY2x1c3RlcmVkIGludG8gY2F0ZWdvcmllcy4gIEV4cGFuZGluZyBpbmRpdmlkdWFsIGNhdGVnb3JpZXMgd2lsbCBzaG93IGFsbCB0aGUgb3B0aW9uIGF2YWlsYWJsZS4gIEZ1cnRoZXIgZXhwYW5kaW5nIGFuIGluZGl2aWR1YWwgY29tbWFuZCB3aWxsIHNob3cgZGV0YWlsZWQgZG9jdW1lbnRhdGlvbiBmb3IgdGhlIGZ1bmN0aW9uLCBpbnB1dCwgb3V0cHV0cyBhbmQgYWxsb3cgeW91IHRvIHRyeSBhbmQgcnVuIHRoZSBmdW5jdGlvbi4gIFJ1bm5pbmcgdGhlIGZ1bmN0aW9uIHdpbGwgc2hvdyB0aGUgdXJsIHVzZWQgZm9yIHRoZSBxdWVyeSBhbmQgYWxsIHJldHVybmVkIHJlc3BvbnNlcy4gCmBgYHtyIGV2YWw9RkFMU0V9CmN5cmVzdEFQSSgpICAjIEN5UkVTVCBBUEkKYGBgCgpBcyBtZW50aW9uZWQgYWJvdmUsIHRoZXJlIGFyZSB0d28gd2F5cyB0byBpbnRlcmFjdCB3aXRoIEN5dG9zY2FwZSwgdGhyb3VnaCB0aGUgQ3lyZXN0IEFQSSBvciBjb21tYW5kcy4gIFRvIHNlZSB0aGUgYXZhaWxhYmxlIGNvbW1hbmRzIGluIHN3YWdnZXIgc2ltaWxhciB0byB0aGUgQ3lyZXN0IEFQSS4KYGBge3IgZXZhbD1GQUxTRX0KY29tbWFuZHNBUEkoKSAgIyBDb21tYW5kcyBBUEkKYGBgCgpUbyBnZXQgaW5mb3JtYXRpb24gYWJvdXQgYW4gaW5kaXZpZHVhbCBjb21tYW5kIGZyb20gdGhlIFIgZW52aXJvbm1lbnQgeW91IGNhbiBhbHNvIHVzZSB0aGUgY29tbWFuZHNIZWxwIGZ1bmN0aW9uLiAgU2ltcGx5IHNwZWNpZnkgd2hhdCBjb21tYW5kIHlvdSB3b3VsZCBsaWtlIHRvIGdldCBpbmZvcm1hdGlvbiBvbiBieSBhZGRpbmcgaXRzIG5hbWUgdG8gdGhlIGNvbW1hbmQuICBGb3IgZXhhbXBsZSAiY29tbWFuZHNIZWxwKCJoZWxwIHN0cmluZyIpIgpgYGB7ciBldmFsPUZBTFNFfQpjb21tYW5kc0hlbHAoImhlbHAiKQpgYGAKCiMjIEN5dG9zY2FwZSBCYXNpY3MKQ3JlYXRlIGEgQ3l0b3NjYXBlIG5ldHdvcmsgZnJvbSBzb21lIGJhc2ljIFIgb2JqZWN0cwpgYGB7cn0Kbm9kZXMgPC0gZGF0YS5mcmFtZShpZD1jKCJub2RlIDAiLCJub2RlIDEiLCJub2RlIDIiLCJub2RlIDMiKSwKICAgICAgICAgICBncm91cD1jKCJBIiwiQSIsIkIiLCJCIiksICMgY2F0ZWdvcmljYWwgc3RyaW5ncwogICAgICAgICAgIHNjb3JlPWFzLmludGVnZXIoYygyMCwxMCwxNSw1KSksICMgaW50ZWdlcnMKICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQplZGdlcyA8LSBkYXRhLmZyYW1lKHNvdXJjZT1jKCJub2RlIDAiLCJub2RlIDAiLCJub2RlIDAiLCJub2RlIDIiKSwKICAgICAgICAgICB0YXJnZXQ9Yygibm9kZSAxIiwibm9kZSAyIiwibm9kZSAzIiwibm9kZSAzIiksCiAgICAgICAgICAgaW50ZXJhY3Rpb249YygiaW5oaWJpdHMiLCJpbnRlcmFjdHMiLCJhY3RpdmF0ZXMiLCJpbnRlcmFjdHMiKSwgICMgb3B0aW9uYWwKICAgICAgICAgICB3ZWlnaHQ9Yyg1LjEsMy4wLDUuMiw5LjkpLCAjIG51bWVyaWMKICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQpgYGAKCmBgYHtyIGV2YWw9RkFMU0V9CmNyZWF0ZU5ldHdvcmtGcm9tRGF0YUZyYW1lcyhub2RlcyxlZGdlcywgdGl0bGU9Im15IGZpcnN0IG5ldHdvcmsiLCBjb2xsZWN0aW9uPSJEYXRhRnJhbWUgRXhhbXBsZSIpCmBgYAoKUmVtZW1iZXIuIEFsbCBuZXR3b3JrcyB3ZSBtYWtlIGFyZSBjcmVhdGVkIGluIEN5dG9zY2FwZSBzbyBnZXQgYW4gaW1hZ2Ugb2YgdGhlIHJlc3VsdGluZyBuZXR3b3JrIGFuZCBpbmNsdWRlIGl0IGluIHlvdXIgY3VycmVudCBhbmFseXNpcyBpZiBkZXNpcmVkLiBXZSBjYW4gZGVmaW5lIGEgZmlsZW5hbWUgdG8gZXhwb3J0IHRvLCBpbiB0aGUgY3VycmVudCBkaXJlY3RvcnkuCgpgYGB7cn0KaW5pdGlhbF9uZXR3b3JrX3BuZ19maWxlX25hbWUgPC0gZmlsZS5wYXRoKGdldHdkKCksImluaXRpYWxfZXhhbXBsZV9uZXR3b3JrLnBuZyIpCmBgYAoKPGNlbnRlcj4KIVtdKGh0dHBzOi8vY3l0b3NjYXBlLmdpdGh1Yi5pby9jeXRvc2NhcGUtYXV0b21hdGlvbi9mb3Itc2NyaXB0ZXJzL1Ivbm90ZWJvb2tzL2Jpb2MyMDE4X1JjeTNfaW50cm8vMjMwX0lzc2VybGluX1JDeTNfaW50cm8vaW1hZ2VzL2luaXRpYWxfZXhhbXBsZV9uZXR3b3JrLnBuZykKPC9jZW50ZXI+CgpgYGB7ciBldmFsPUZBTFNFfQppZihmaWxlLmV4aXN0cyhpbml0aWFsX25ldHdvcmtfcG5nX2ZpbGVfbmFtZSkpewogICNjeXRvc2NhcGUgaGFuZ3Mgd2FpdGluZyBmb3IgdXNlciByZXNwb25zZSBpZiBmaWxlIGFscmVhZHkgZXhpc3RzLiAgUmVtb3ZlIGl0IGZpcnN0CiAgZmlsZS5yZW1vdmUoaW5pdGlhbF9uZXR3b3JrX3BuZ19maWxlX25hbWUpCiAgfSAKCiNleHBvcnQgdGhlIG5ldHdvcmsKZXhwb3J0SW1hZ2UoZmlsZW5hbWU9ImluaXRpYWxfZXhhbXBsZV9uZXR3b3JrLnBuZyIsIHR5cGUgPSAicG5nIikKYGBgCgojIyBFeGFtcGxlIERhdGEgU2V0CldlIGRvd25sb2FkZWQgZ2VuZSBleHByZXNzaW9uIGRhdGEgZnJvbSB0aGUgT3ZhcmlhbiBTZXJvdXMgQ3lzdGFkZW5vY2FyY2lub21hIHByb2plY3Qgb2YgVGhlIENhbmNlciBHZW5vbWUgQXRsYXMgKFRDR0EpW0BUQ0dBXSwgaHR0cDovL2NhbmNlcmdlbm9tZS5uaWguZ292IHZpYSB0aGUgR2Vub21pYyBEYXRhIENvbW1vbnMgKEdEQykgcG9ydGFsW0BHRENdIG9uIDIwMTctMDYtMTQgdXNpbmcgVENHQUJpb2xpbmtzIFIgcGFja2FnZVtAVENHQUJpb2xpbmtzXS4gVGhlIGRhdGEgaW5jbHVkZXMgMzAwIHNhbXBsZXMgYXZhaWxhYmxlIGFzIFJOQS1zZXEgZGF0YSwgd2l0aCByZWFkcyBtYXBwZWQgdG8gYSByZWZlcmVuY2UgZ2Vub21lIHVzaW5nIE1hcFNwbGljZVtATWFwU3BsaWNlXSBhbmQgcmVhZCBjb3VudHMgcGVyIHRyYW5zY3JpcHQgZGV0ZXJtaW5lZCB1c2luZyB0aGUgUlNFTSBtZXRob2RbQFJTRU1dLiBSTkEtc2VxIGRhdGEgYXJlIGxhYmVsZWQgYXMg4oCYUk5BLVNlcSBWMuKAmSwgc2VlIGRldGFpbHMgYXQ6IGh0dHBzOi8vd2lraS5uY2kubmloLmdvdi9kaXNwbGF5L1RDR0EvUk5BU2VxK1ZlcnNpb24rMikuIFRoZSBSTkEtU2VxVjIgZGF0YSBjb25zaXN0cyBvZiByYXcgY291bnRzIHNpbWlsYXIgdG8gcmVndWxhciBSTkEtc2VxIGJ1dCBSU0VNIChSTkEtU2VxIGJ5IEV4cGVjdGF0aW9uIE1heGltaXphdGlvbikgZGF0YSBjYW4gYmUgdXNlZCB3aXRoIHRoZSBlZGdlUiBtZXRob2QuIFRoZSBleHByZXNzaW9uIGRhdGFzZXQgb2YgMzAwIHR1bW91cnMsIHdpdGggNzkgY2xhc3NpZmllZCBhcyBJbW11bm9yZWFjdGl2ZSwgNzIgY2xhc3NpZmllZCBhcyBNZXNlbmNoeW1hbCwgNjkgY2xhc3NpZmllZCBhcyBEaWZmZXJlbnRpYXRlZCwgYW5kIDgwIGNsYXNzaWZpZWQgYXMgUHJvbGlmZXJhdGl2ZSBzYW1wbGVzKGNsYXNzIGRlZmluaXRpb25zIHdlcmUgb2J0YWluZWQgZnJvbSBWZXJoYWFrIGV0IGFsLltAT1ZdIFN1cHBsZW1lbnRhcnkgVGFibGUgMSwgdGhpcmQgY29sdW1uKS4gUk5BLXNlcSByZWFkIGNvdW50cyB3ZXJlIGNvbnZlcnRlZCB0byBDUE0gdmFsdWVzIGFuZCBnZW5lcyB3aXRoIENQTSA+IDEgaW4gYXQgbGVhc3QgNTAgb2YgdGhlIHNhbXBsZXMgYXJlIHJldGFpbmVkIGZvciBmdXJ0aGVyIHN0dWR5ICg1MCBpcyB0aGUgbWluaW1hbCBzYW1wbGUgc2l6ZSBpbiB0aGUgY2xhc3NlcykuICBUaGUgZGF0YSB3YXMgbm9ybWFsaXplZCBhbmQgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gd2FzIGNhbGN1bGF0ZWQgZm9yIGVhY2ggY2FuY2VyIGNsYXNzIHJlbGF0aXZlIHRvIHRoZSByZXN0IG9mIHRoZSBzYW1wbGVzLiAKClRoZXJlIGFyZSB0d28gZGF0YSBmaWxlczoKIDEuIEV4cHJlc3Npb24gbWF0cml4IC0gY29udGFpbmluZyB0aGUgbm9ybWFsaXplZCBleHByZXNzaW9uIGZvciBlYWNoIGdlbmUgYWNyb3NzIGFsbCAzMDAgc2FtcGxlcy4KIDEuIEdlbmUgcmFua3MgLSBjb250YWluaW5nIHRoZSBwLXZhbHVlcywgRkRSIGFuZCBmb2xkY2hhbmdlIHZhbHVlcyBmb3IgdGhlIDQgY29tcGFyaXNvbnMgKG1lc2VuY2h5bWFsIHZzIHJlc3QsIGRpZmZlcmVudGlhbCB2cyByZXN0LCBwcm9saWZlcmF0aXZlIHZzIHJlc3QgYW5kIGltbXVub3JlYWN0aXZlIHZzIHJlc3QpCgpUaGUgZm9sbG93aW5nIGNvbW1hbmRzIHdpbGwgY3JlYXRlIGEgbmV3IGRpcmVjdG9yeSBpbiB5b3VyIGN1cnJlbnQgZGlyZWN0b3J5LCBhbmQgZG93bmxvYWQgdGhlIGRhdGEgZmlsZXMgdG8gaXQuCmBgYHtyfQojY3JlYXRlIGEgc291cmNlIGRpcmVjdG9yeSBmb3IgdGhlIGRvd25sb2FkCmRpci5jcmVhdGUoZmlsZS5wYXRoKGdldHdkKCksIjIzMF9Jc3Nlcmxpbl9SQ3kzX2ludHJvIikpCgojZGVmaW5lIGxvY2F0aW9ucyBmb3IgZG93bmxvYWQKdXJsX2V4cCA8LSAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2N5dG9zY2FwZS9jeXRvc2NhcGUtdHV0b3JpYWxzL2doLXBhZ2VzL3ByZXNlbnRhdGlvbnMvbW9kdWxlcy9SQ3kzX0V4YW1wbGVEYXRhL2RhdGEvVENHQV9PVl9STkFzZXFfZXhwcmVzc2lvbi50eHQiCnBhdGhfZXhwIDwtIGZpbGUucGF0aChnZXR3ZCgpLCIyMzBfSXNzZXJsaW5fUkN5M19pbnRybyIsICJUQ0dBX09WX1JOQXNlcV9leHByZXNzaW9uLnR4dCIpCgp1cmxfc2NvcmVzIDwtImh0dHBzOi8vZ2l0aHViLmNvbS9jeXRvc2NhcGUvY3l0b3NjYXBlLXR1dG9yaWFscy9ibG9iL2doLXBhZ2VzL3ByZXNlbnRhdGlvbnMvbW9kdWxlcy9SQ3kzX0V4YW1wbGVEYXRhL2RhdGEvVENHQV9PVl9STkFzZXFfQWxsX2VkZ2VSX3Njb3Jlcy50eHQ/cmF3PXRydWUiCnBhdGhfc2NvcmVzIDwtIGZpbGUucGF0aChnZXR3ZCgpLCIyMzBfSXNzZXJsaW5fUkN5M19pbnRybyIsICJUQ0dBX09WX1JOQXNlcV9BbGxfZWRnZVJfc2NvcmVzLnR4dCIpCgojZG93bmxvYWQgZmlsZXMKZG93bmxvYWQuZmlsZSh1cmxfZXhwLCBwYXRoX2V4cCkKZG93bmxvYWQuZmlsZSh1cmxfc2NvcmVzLCBwYXRoX3Njb3JlcykKYGBgCgpOb3cgd2UgY2FuIHJlYWQgdGhlIGRvd25sb2FkZWQgZmlsZXMgaW50byBSOgpgYGB7cn0KUk5BU2VxX2V4cHJlc3Npb25fbWF0cml4IDwtIHJlYWQudGFibGUocGF0aF9leHAsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICJcdCIsIHF1b3RlPSJcIiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKClJOQVNlcV9nZW5lX3Njb3JlcyA8LSByZWFkLnRhYmxlKHBhdGhfc2NvcmVzLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiXHQiLCBxdW90ZT0iXCIiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCmBgYAoKIyMgRmluZGluZyBOZXR3b3JrIERhdGEKSG93IGRvIEkgcmVwcmVzZW50ICpteSogZGF0YSBhcyBhIG5ldHdvcms/CgpVbmZvcnR1bmF0ZWx5LCB0aGVyZSBpcyBub3QgYSBzaW1wbGUgYW5zd2VyLiAgKipJdCBkZXBlbmRzIG9uIHlvdXIgYmlvbG9naWNhbCBxdWVzdGlvbiEqKiAgIAoKRXhhbXBsZSB1c2UgY2FzZXM6CgogMS4gT21pY3MgZGF0YSAtIEkgaGF2ZSBhICpmaWxsIGluIHRoZSBibGFuayogKG1pY3JvYXJyYXksIFJOQVNlcSwgUHJvdGVvbWljcywgQVRBQ3NlcSwgTWljcm9STkEsIEdXQVMgLi4uKSBkYXRhc2V0LiAgSSBoYXZlIG5vcm1hbGl6ZWQgYW5kIHNjb3JlZCBteSBkYXRhLiBIb3cgZG8gSSBvdmVybGF5IG15IGRhdGEgb24gZXhpc3RpbmcgaW50ZXJhY3Rpb24gZGF0YT8gCiAxLiBDb2V4cHJlc3Npb24gZGF0YSAtIEkgaGF2ZSBhIGRhdGFzZXQgdGhhdCByZXByZXNlbnRzIHJlbGF0aW9uc2hpcHMuICBIb3cgZG8gSSByZXByZXNlbnQgaXQgYXMgYSBuZXR3b3JrLiAKCiMgVXNlIENhc2UgMSAtIEhvdyBhcmUgbXkgdG9wIGdlbmVzIHJlbGF0ZWQ/CgpPbWljcyBkYXRhIC0gSSBoYXZlIGEgKmZpbGwgaW4gdGhlIGJsYW5rKiAobWljcm9hcnJheSwgUk5BU2VxLCBQcm90ZW9taWNzLCBBVEFDc2VxLCBNaWNyb1JOQSwgR1dBUyAuLi4pIGRhdGFzZXQuICBJIGhhdmUgbm9ybWFsaXplZCBhbmQgc2NvcmVkIG15IGRhdGEuIEhvdyBkbyBJIG92ZXJsYXkgbXkgZGF0YSBvbiBleGlzdGluZyBpbnRlcmFjdGlvbiBkYXRhPyAKClRoZXJlIGFyZSBlbmRsZXNzIGFtb3VudHMgb2YgZGF0YWJhc2VzIHN0b3JpbmcgaW50ZXJhY3Rpb24gZGF0YS4gCgo8Y2VudGVyPgohW10oaHR0cHM6Ly9jeXRvc2NhcGUuZ2l0aHViLmlvL2N5dG9zY2FwZS1hdXRvbWF0aW9uL2Zvci1zY3JpcHRlcnMvUi9ub3RlYm9va3MvYmlvYzIwMThfUmN5M19pbnRyby8yMzBfSXNzZXJsaW5fUkN5M19pbnRyby9pbWFnZXMvaW50ZXJhY3Rpb24tZGJzLnBuZykKPC9jZW50ZXI+CgpUaGFua2Z1bGx5IHdlIGRvbid0IGhhdmUgdG8gcXVlcnkgZWFjaCBpbmRlcGVuZGVudCBhbGx5LiAgSW4gYWRkaXRpb24gdG8gbWFueSBzcGVjaWFsaXplZCAoZm9yIGV4YW1wbGUsIGZvciBzcGVjaWZpYyBtb2xlY3VsZXMsIGludGVyYWN0aW9uIHR5cGUsIG9yIHNwZWNpZXMpIGludGVyYWN0aW9uIGRhdGFiYXNlcyB0aGVyZSBhcmUgYWxzbyBkYXRhYmFzZXMgdGhhdCBjb2xsYXRlIHRoZXNlIGRhdGFiYXNlcyB0byBjcmVhdGUgYSBicm9hZCByZXNvdXJjZSB0aGF0IGlzIGVhc2llciB0byB1c2UuIEZvciBleGFtcGxlOgoKICogW1N0cmluZ0FwcF0oaHR0cDovL2FwcHMuY3l0b3NjYXBlLm9yZy9hcHBzL3N0cmluZ2FwcCkgLSBpcyBhIHByb3RlaW4gLSBwcm90ZWluIGFuZCBwcm90ZWluLSBjaGVtaWNhbCBkYXRhYmFzZSB0aGF0IGltcG9ydHMgZGF0YSBmcm9tIFtTdHJpbmddKHN0cmluZy1kYi5vcmcpW0BzdHJpbmddICh3aGljaCBpdHNlbGYgaW5jbHVkZXMgZGF0YSBmcm9tIG11bHRpcGxlIHNwZWNpZXMsIGNvZXhwcmVzc2lvbiwgdGV4dC1taW5pbmcsZXhpc3RpbmcgZGF0YWJhc2VzLCBhbmQgZ2Vub21pYyBjb250ZXh0KSwgW1NUSVRDSF0gaW50byBhIHVuaWZpZWQsIHF1ZXJpYWJsZSBkYXRhYmFzZS4KICogW1BTSUNRVUlDXShodHRwczovL3BzaWNxdWljLmdpdGh1Yi5pby8pW0Bwc2ljcXVpY10gLSBhIFJFU1QtZnVsIHNlcnZpY2UgdGhhdCBpcyB0aGUgcmVzcG9uc2liaWxpdHkgb2YgdGhlIGRhdGFiYXNlIHByb3ZpZGVyIHRvIHNldCB1cCBhbmQgbWFpbnRhaW4uICBQU0lDUVVJQyBpcyBhbiBhZGRpdGlvbmFsIGludGVyZmFjZSB0aGF0IGFsbG93cyB1c2VycyB0byBzZWFyY2ggYWxsIGF2YWlsYWJsZSBkYXRhYmFzZXMgKHRoYXQgc3VwcG9ydCB0aGlzIFJFU1QtZnVsIHNlcnZpY2UpLiAgVGhlIGRhdGFiYXNlcyBhcmUgcmVxdWlyZWQgdG8gcmVwcmVzZW50IHRoZWlyIGludGVyYWN0aW9uIGRhdGEgaW4gUHJvdGVvbWljIFN0YW5kYXJkcyBJbml0aWF0aXZlIC0gbW9sZWN1bGFyIGludGVyYWN0aW9uIChQU0ktTUkpIGZvcm1hdC4gVG8gc2VlIGEgbGlzdCBvZiBhbGwgdGhlIGF2YWlsYWJsZSBkYXRhIHNvdXJjZSBzZWUgW2hlcmVdKGh0dHA6Ly93d3cuZWJpLmFjLnVrL1Rvb2xzL3dlYnNlcnZpY2VzL3BzaWNxdWljL3JlZ2lzdHJ5L3JlZ2lzdHJ5P2FjdGlvbj1TVEFUVVMpCiAqIFtuRGV4XShodHRwOi8vaG9tZS5uZGV4YmlvLm9yZy9pbmRleC8pW0BuZGV4XSAtIGEgbmV0d29yayBkYXRhIGV4Y2hhbmdlIHJlcG9zaXRvcnkuIAogKiBbR2VuZU1BTklBXShodHRwOi8vZ2VuZW1hbmlhLm9yZy8pW0BnZW5lbWFuaWFdIC0gY29udGFpbnMgbXVsdGlwbGUgbmV0d29ya3MgKHNoYXJlZCBkb21haW5zLCBwaHlzaWNhbCBpbnRlcmFjdGlvbnMsIHBhdGh3YXlzLCBwcmVkaWN0ZWQsIGNvLWV4cHJlc3Npb24sIGdlbmV0aWMgaW50ZXJhY3Rpb25zIGFuZCBjby1sb2NhbGl6ZWQgbmV0d29yaykuICBHaXZlbiBhIHNldCBvZiBnZW5lcyBHZW5lTUFOSUEgc2VsZWN0cyBhbmQgd2VpZ2h0cyBuZXR3b3JrcyB0aGF0IG9wdGltaXplIHRoZSBjb25uZWN0aXZpdHkgYmV0d2VlbiB0aGUgcXVlcnkgZ2VuZXMuICBHZW5lTUFOSUEgd2lsbCBhbHNvIHJldHVybiBhZGRpdGlvbmFsIGdlbmVzIHRoYXQgYXJlIGhpZ2hseSByZWxhdGVkIHRvIHlvdXIgcXVlcnkgc2V0LgogKiBbUGF0aHdheUNvbW1vbnNdKGh0dHA6Ly93d3cucGF0aHdheWNvbW1vbnMub3JnLykgLSAoYWNjZXNzIHRoZSBkYXRhIHRocm91Z2ggdGhlIFtDeVBhdGgyQXBwXShodHRwOi8vYXBwcy5jeXRvc2NhcGUub3JnL2FwcHMvY3lwYXRoMikpIGlzIGEgcGF0aHdheSBhbmQgaW50ZXJhY3Rpb24gZGF0YSBzb3VyY2UuICBEYXRhIGlzIGNvbGxhdGVkIGZyb20gYSBsYXJnZSBzZXQgb2YgcmVzb3VyY2VzIChsaXN0IFtoZXJlXShodHRwOi8vd3d3LnBhdGh3YXljb21tb25zLm9yZy9wYzIvZGF0YXNvdXJjZXMpICkgYW5kIHN0b3JlZCBpbiB0aGUgQmlvUEFYW0BiaW9wYXhdIGZvcm1hdC4gIEJpb1BBWCBpcyBhIGRhdGEgc3RhbmRhcmQgdGhhdCBhbGxvd3MgZm9yIGRldGFpbGVkIHJlcHJlc2VudGF0aW9uIG9mIHBhdGh3YXkgbWVjaGFuaXN0aWMgZGV0YWlscyBhcyBvcHBvc2VkIHRvIGNvbGxhcHNpbmcgaXQgdG8gdGhlIHNldCBvZiBpbnRlcmFjdGlvbnMgYmV0d2VlbiBtb2xlY3VsZXMuICBCaW9QQVggcGF0aHdheXMgZnJvbSBQYXRod2F5IGNvbW1vbnMgY2FuIGFsc28gYmUgbG9hZGVkIGRpcmVjdGx5IGludG8gUiB1c2luZyB0aGUgW1BheFRvb2xzUl0oaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvcGF4dG9vbHNyLmh0bWwpW0BwYXh0b29sc3JdIEJpb2NvbmR1Y3RvciBwYWNrYWdlLiAgIAoKR2V0IGEgc3Vic2V0IG9mIGdlbmVzIG9mIGludGVyZXN0IGZyb20gb3VyIHNjb3JlZCBkYXRhOgpgYGB7cn0KdG9wX21lc2VuY2h5bWFsX2dlbmVzIDwtIFJOQVNlcV9nZW5lX3Njb3Jlc1t3aGljaChSTkFTZXFfZ2VuZV9zY29yZXMkRkRSLm1lc2VuIDwgMC4wNSAmIFJOQVNlcV9nZW5lX3Njb3JlcyRsb2dGQy5tZXNlbiA+IDIpLF0KaGVhZCh0b3BfbWVzZW5jaHltYWxfZ2VuZXMpCmBgYAoKV2UgYXJlIGdvaW5nIHRvIHF1ZXJ5IHRoZSBTdHJpbmcgRGF0YWJhc2UgdG8gZ2V0IGFsbCBpbnRlcmFjdGlvbnMgZm91bmQgZm9yIG91ciBzZXQgb2YgdG9wIE1lc2VuY2h5bWFsIGdlbmVzLgoKUmVtaW5kZXI6IHRvIHNlZSB0aGUgcGFyYW1ldGVycyByZXF1aXJlZCBieSB0aGUgc3RyaW5nIGZ1bmN0aW9uIG9yIHRvIGZpbmQgdGhlIHJpZ2h0IHN0cmluZyBmdW5jdGlvbiB5b3UgY2FuIHVzZSBjb21tYW5kc0hlbHAuCmBgYHtyIGV2YWw9RkFMU0V9CmNvbW1hbmRzSGVscCgiaGVscCBzdHJpbmciKQpgYGAKCmBgYHtyIGV2YWw9RkFMU0V9CmNvbW1hbmRzSGVscCgiaGVscCBzdHJpbmcgcHJvdGVpbiBxdWVyeSIpCmBgYAoKYGBge3IgZXZhbD1GQUxTRX0KbWVzZW5fc3RyaW5nX2ludGVyYWN0aW9uX2NtZCA8LSBwYXN0ZSgnc3RyaW5nIHByb3RlaW4gcXVlcnkgdGF4b25JRD05NjA2IGxpbWl0PTE1MCBjdXRvZmY9MC45IHF1ZXJ5PSInLHBhc3RlKHRvcF9tZXNlbmNoeW1hbF9nZW5lcyROYW1lLCBjb2xsYXBzZT0iLCIpLCciJyxzZXA9IiIpCmNvbW1hbmRzR0VUKG1lc2VuX3N0cmluZ19pbnRlcmFjdGlvbl9jbWQpCmBgYAoKR2V0IGEgc2NyZWVuc2hvdCBvZiB0aGUgaW5pdGlhbCBuZXR3b3JrCmBgYHtyIGluaXRpYWxfc3RyaW5nX25ldHdvcmtfc2NyZWVuc2hvdCwgaW5jbHVkZT1UUlVFfQppbml0aWFsX3N0cmluZ19uZXR3b3JrX3BuZ19maWxlX25hbWUgPC0gZmlsZS5wYXRoKGdldHdkKCksIjIzMF9Jc3Nlcmxpbl9SQ3kzX2ludHJvIiwgImluaXRpYWxfc3RyaW5nX25ldHdvcmsucG5nIikKYGBgCgpgYGB7ciBldmFsPUZBTFNFfQppZihmaWxlLmV4aXN0cyhpbml0aWFsX3N0cmluZ19uZXR3b3JrX3BuZ19maWxlX25hbWUpKXsKICAjY3l0b3NjYXBlIGhhbmdzIHdhaXRpbmcgZm9yIHVzZXIgcmVzcG9uc2UgaWYgZmlsZSBhbHJlYWR5IGV4aXN0cy4gIFJlbW92ZSBpdCBmaXJzdAogIHJlc3BvbnNlIDwtIGZpbGUucmVtb3ZlKGluaXRpYWxfc3RyaW5nX25ldHdvcmtfcG5nX2ZpbGVfbmFtZSkKfSAKCnJlc3BvbnNlIDwtIGV4cG9ydEltYWdlKGluaXRpYWxfc3RyaW5nX25ldHdvcmtfcG5nX2ZpbGVfbmFtZSwgdHlwZSA9ICJwbmciKQpgYGAKCmBgYHtyIGluaXRpYWxzdHJpbmduZXR3b3JrLCBlY2hvPUZBTFNFLCBmaWcuY2FwPSJJbml0aWFsIG5ldHdvcmsgcmV0dXJuZWQgYnkgU3RyaW5nIGZyb20gb3VyIHNldCBvZiBNZXNlbmNoeW1hbCBxdWVyeSBnZW5lcyJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGluaXRpYWxfc3RyaW5nX25ldHdvcmtfcG5nX2ZpbGVfbmFtZSkKYGBgCgpMYXlvdXQgdGhlIG5ldHdvcmsKYGBge3IgZXZhbD1GQUxTRX0KbGF5b3V0TmV0d29yaygnZm9yY2UtZGlyZWN0ZWQnKQpgYGAKCkNoZWNrIHdoYXQgb3RoZXIgbGF5b3V0IGFsZ29yaXRobXMgYXJlIGF2YWlsYWJsZSB0byB0cnkgb3V0CmBgYHtyIGV2YWw9RkFMU0V9CmdldExheW91dE5hbWVzKCkKYGBgCgpHZXQgdGhlIHBhcmFtZXRlcnMgZm9yIGEgc3BlY2lmaWMgbGF5b3V0CmBgYHtyIGV2YWw9RkFMU0V9CmdldExheW91dFByb3BlcnR5TmFtZXMobGF5b3V0Lm5hbWU9J2ZvcmNlLWRpcmVjdGVkJykKYGBgCgpSZS1sYXlvdXQgdGhlIG5ldHdvcmsgdXNpbmcgdGhlIGZvcmNlIGRpcmVjdGVkIGxheW91dCBidXQgc3BlY2lmeSBzb21lIG9mIHRoZSBwYXJhbWV0ZXJzIApgYGB7ciBldmFsPUZBTFNFfQpsYXlvdXROZXR3b3JrKCdmb3JjZS1kaXJlY3RlZCBkZWZhdWx0U3ByaW5nQ29lZmZpY2llbnQ9MC4wMDAwMDA4IGRlZmF1bHRTcHJpbmdMZW5ndGg9NzAnKQpgYGAKCkdldCBhIHNjcmVlbnNob3Qgb2YgdGhlIHJlLWxhaWQgb3V0IG5ldHdvcmsKYGBge3IgcmVsYXlvdXRfc3RyaW5nX25ldHdvcmtfc2NyZWVuc2hvdCwgaW5jbHVkZT1UUlVFfQpyZWxheW91dF9zdHJpbmdfbmV0d29ya19wbmdfZmlsZV9uYW1lIDwtIGZpbGUucGF0aChnZXR3ZCgpLCIyMzBfSXNzZXJsaW5fUkN5M19pbnRybyIsICJyZWxheW91dF9zdHJpbmdfbmV0d29yay5wbmciKQpgYGAKCmBgYHtyIGV2YWw9RkFMU0V9CmlmKGZpbGUuZXhpc3RzKHJlbGF5b3V0X3N0cmluZ19uZXR3b3JrX3BuZ19maWxlX25hbWUpKXsKICAjY3l0b3NjYXBlIGhhbmdzIHdhaXRpbmcgZm9yIHVzZXIgcmVzcG9uc2UgaWYgZmlsZSBhbHJlYWR5IGV4aXN0cy4gIFJlbW92ZSBpdCBmaXJzdAogIHJlc3BvbnNlPC0gZmlsZS5yZW1vdmUocmVsYXlvdXRfc3RyaW5nX25ldHdvcmtfcG5nX2ZpbGVfbmFtZSkKICB9IApyZXNwb25zZSA8LSBleHBvcnRJbWFnZShyZWxheW91dF9zdHJpbmdfbmV0d29ya19wbmdfZmlsZV9uYW1lLCB0eXBlID0gInBuZyIpCmBgYAoKYGBge3IgcmVsYXlvdXRzdHJpbmduZXR3b3JrLCBlY2hvPUZBTFNFLCBmaWcuY2FwPSJJbml0aWFsIG5ldHdvcmsgcmV0dXJuZWQgYnkgU3RyaW5nIGZyb20gb3VyIHNldCBvZiBNZXNlbmNoeW1hbCBxdWVyeSBnZW5lcyJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKHJlbGF5b3V0X3N0cmluZ19uZXR3b3JrX3BuZ19maWxlX25hbWUpCmBgYAoKT3ZlcmxheSBvdXIgZXhwcmVzc2lvbiBkYXRhIG9uIHRoZSBTdHJpbmcgbmV0d29yay4gIApUbyBkbyB0aGlzIHdlIHdpbGwgYmUgdXNpbmcgdGhlIGxvYWRUYWJsZURhdGEgZnVuY3Rpb24gZnJvbSBSQ3kzLiBJdCBpcyBpbXBvcnRhbnQgdG8gbWFrZSBzdXJlIHRoYXQgIHRoYXQgeW91ciBpZGVudGlmaWVycyB0eXBlcyBtYXRjaCB1cC4gIFlvdSBjYW4gY2hlY2sgd2hhdCBpcyB1c2VkIGJ5IFN0cmluZyBieSBwdWxsaW5nIGluIHRoZSBjb2x1bW4gbmFtZXMgb2YgdGhlIG5vZGUgYXR0cmlidXRlIHRhYmxlLgoKYGBge3IgZXZhbD1GQUxTRX0KZ2V0VGFibGVDb2x1bW5OYW1lcygnbm9kZScpCmBgYAoKSWYgeW91IGFyZSB1bnN1cmUgb2Ygd2hhdCBlYWNoIGNvbHVtbiBpcyBhbmQgd2FudCB0byBmdXJ0aGVyIHZlcmlmeSB0aGUgY29sdW1uIHRvIHVzZSB5b3UgY2FuIGFsc28gcHVsbCBpbiB0aGUgZW50aXJlIG5vZGUgYXR0cmlidXRlIHRhYmxlLgpgYGB7ciBldmFsPUZBTFNFfQpub2RlX2F0dHJpYnV0ZV90YWJsZV90b3BtZXNlbiA8LSBnZXRUYWJsZUNvbHVtbnModGFibGU9Im5vZGUiKQpoZWFkKG5vZGVfYXR0cmlidXRlX3RhYmxlX3RvcG1lc2VuWywzOjddKQpgYGAKClRoZSBjb2x1bW4gImRpc3BsYXkgbmFtZSIgY29udGFpbnMgSEdOQyBnZW5lIG5hbWVzIHdoaWNoIGFyZSBhbHNvIGZvdW5kIGluIG91ciBPdmFyaWFuIENhbmNlciBkYXRhc2V0LgoKVG8gaW1wb3J0IG91ciBleHByZXNzaW9uIGRhdGEgd2Ugd2lsbCBtYXRjaCBvdXIgZGF0YXNldCB0byB0aGUgImRpc3BsYXkgbmFtZSIgbm9kZSBhdHRyaWJ1dGUuCgpgYGB7ciBldmFsPUZBTFNFfQo/bG9hZFRhYmxlRGF0YQoKbG9hZFRhYmxlRGF0YShSTkFTZXFfZ2VuZV9zY29yZXMsdGFibGUua2V5LmNvbHVtbiA9ICJkaXNwbGF5IG5hbWUiLGRhdGEua2V5LmNvbHVtbiA9ICJOYW1lIikgICNkZWZhdWx0IGRhdGEuZnJhbWUga2V5IGlzIHJvdy5uYW1lcwpgYGAKCk1vZGlmeSB0aGUgVmlzdWFsIFN0eWxlCkNyZWF0ZSB5b3VyIG93biB2aXN1YWwgc3R5bGUgdG8gdmlzdWFsaXplIHlvdXIgZXhwcmVzc2lvbiBkYXRhIG9uIHRoZSBTdHJpbmcgbmV0d29yay4gCgpTdGFydCB3aXRoIGEgZGVmYXVsdCBzdHlsZQpgYGB7ciBldmFsPUZBTFNFfQpzdHlsZS5uYW1lID0gIk1lc2VuY2h5bWFsU3R5bGUiCmRlZmF1bHRzLmxpc3QgPC0gbGlzdChOT0RFX1NIQVBFPSJlbGxpcHNlIiwKICAgICAgICAgICAgICAgICBOT0RFX1NJWkU9NjAsCiAgICAgICAgICAgICAgICAgTk9ERV9GSUxMX0NPTE9SPSIjQUFBQUFBIiwKICAgICAgICAgICAgICAgICBFREdFX1RSQU5TUEFSRU5DWT0xMjApCm5vZGUubGFiZWwubWFwIDwtIG1hcFZpc3VhbFByb3BlcnR5KCdub2RlIGxhYmVsJywnZGlzcGxheSBuYW1lJywncCcpICMgcCBmb3IgcGFzc3Rocm91Z2g7IG5vdGhpbmcgZWxzZSBuZWVkZWQKY3JlYXRlVmlzdWFsU3R5bGUoc3R5bGUubmFtZSwgZGVmYXVsdHMubGlzdCwgbGlzdChub2RlLmxhYmVsLm1hcCkpCnNldFZpc3VhbFN0eWxlKHN0eWxlLm5hbWU9c3R5bGUubmFtZSkKYGBgCgpVcGRhdGUgeW91ciBjcmVhdGVkIHN0eWxlIHdpdGggYSBtYXBwaW5nIGZvciB0aGUgTWVzZW5jaHltYWwgbG9nRkMgZXhwcmVzc2lvbi4gVGhlIGZpcnN0IHN0ZXAgaXMgdG8gZ3JhYiB0aGUgY29sdW1uIGRhdGEgZnJvbSBDeXRvc2NhcGUgKHdlIGNhbiByZXVzZSB0aGUgbm9kZV9hdHRyaWJ1dGUgdGFibGUgY29uY2VwdCBmcm9tIGFib3ZlIGJ1dCB3ZSBoYXZlIHRvIGNhbGwgdGhlIGZ1bmN0aW9uIGFnYWluIGFzIHdlIGhhdmUgc2luY2UgYWRkZWQgb3VyIGV4cHJlc3Npb24gZGF0YSkgYW5kIHB1bGwgb3V0IHRoZSBtaW4gYW5kIG1heCB0byBkZWZpbmUgb3VyIGRhdGEgbWFwcGluZyByYW5nZSBvZiB2YWx1ZXMuCgoqKk5vdGUqKjogeW91IGNvdWxkIGRlZmluZSB0aGUgbWluIGFuZCBtYXggYmFzZWQgb24gdGhlIGVudGlyZSBkYXRhc2V0IG9yIGp1c3QgdGhlIHN1YnNldCB0aGF0IGlzIHJlcHJlc2VudGVkIGluIEN5dG9zY2FwZSBjdXJyZW50bHkuICBUaGUgdHdvIG1ldGhvZHMgd2lsbCBnaXZlIHlvdSBkaWZmZXJlbnQgcmVzdWx0cy4gIElmIHlvdSBpbnRlbmQgb24gY29tcGFyaW5nIGRpZmZlcmVudCBuZXR3b3JrcyBjcmVhdGVkIHdpdGggdGhlIHNhbWUgZGF0YXNldCB0aGVuIGl0IGlzIGJlc3QgdG8gY2FsY3VsYXRlIHRoZSBtaW4gYW5kIG1heCBmcm9tIHRoZSBlbnRpcmUgZGF0YXNldCBhcyBvcHBvc2VkIHRvIGEgc3Vic2V0LiAKCmBgYHtyfQptaW4ubWVzZW4ubG9nZmMgPSBtaW4oUk5BU2VxX2dlbmVfc2NvcmVzJGxvZ0ZDLm1lc2VuLG5hLnJtPVRSVUUpCm1heC5tZXNlbi5sb2dmYyA9IG1heChSTkFTZXFfZ2VuZV9zY29yZXMkbG9nRkMubWVzZW4sbmEucm09VFJVRSkKZGF0YS52YWx1ZXMgPSBjKG1pbi5tZXNlbi5sb2dmYywwLG1heC5tZXNlbi5sb2dmYykKYGBgCgoKTmV4dCwgd2UgdXNlIHRoZSBSQ29sb3JCcmV3ZXIgcGFja2FnZSB0byBoZWxwIHVzIHBpY2sgZ29vZCBjb2xvcnMgdG8gcGFpciB3aXRoIG91ciBkYXRhIHZhbHVlcy4KYGBge3J9CmxpYnJhcnkoUkNvbG9yQnJld2VyKQpkaXNwbGF5LmJyZXdlci5hbGwobGVuZ3RoKGRhdGEudmFsdWVzKSwgY29sb3JibGluZEZyaWVuZGx5PVRSVUUsIHR5cGU9ImRpdiIpICMgZGl2LHF1YWwsc2VxLGFsbApub2RlLmNvbG9ycyA8LSBjKHJldihicmV3ZXIucGFsKGxlbmd0aChkYXRhLnZhbHVlcyksICJSZEJ1IikpKQpgYGAKCk1hcCB0aGUgY29sb3JzIHRvIG91ciBkYXRhIHZhbHVlIGFuZCB1cGRhdGUgb3VyIHZpc3VhbCBzdHlsZS4gCmBgYHtyIGV2YWw9RkFMU0V9IApzZXROb2RlQ29sb3JNYXBwaW5nKCJsb2dGQy5tZXNlbiIsIGRhdGEudmFsdWVzLCBub2RlLmNvbG9ycywgc3R5bGUubmFtZT1zdHlsZS5uYW1lKQpgYGAKClJlbWVtYmVyLCBTdHJpbmcgaW5jbHVkZXMgeW91ciBxdWVyeSBwcm90ZWlucyBhcyB3ZWxsIGFzIG90aGVyIHByb3RlaW5zIHRoYXQgYXNzb2NpYXRlIHdpdGggeW91ciBxdWVyeSBwcm90ZWlucyAoaW5jbHVkaW5nIHRoZSBzdHJvbmdlc3QgY29ubmVjdGlvbiBmaXJzdCkuICBOb3QgYWxsIG9mIHRoZSBwcm90ZWlucyBpbiB0aGlzIG5ldHdvcmsgYXJlIHlvdXIgdG9wIGhpdHMuICBIb3cgY2FuIHdlIHZpc3VhbGl6ZSB3aGljaCBwcm90ZWlucyBhcmUgb3VyIHRvcCBNZXNlbmNoeW1hbCBoaXRzPwoKQWRkIGEgZGlmZmVyZW50IGJvcmRlciBjb2xvciBvciBjaGFuZ2UgdGhlIG5vZGUgc2hhcGUgZm9yIG91ciB0b3AgaGl0cy4KCmBgYHtyIGV2YWw9RkFMU0V9CmdldE5vZGVTaGFwZXMoKQoKI3NlbGVjdCB0aGUgTm9kZXMgb2YgaW50ZXJlc3QKI3NlbGVjdE5vZGUobm9kZXMgPSB0b3BfbWVzZW5jaHltYWxfZ2VuZXMkTmFtZSwgYnkuY29sPSJkaXNwbGF5IG5hbWUiKQpzZXROb2RlU2hhcGVCeXBhc3Mobm9kZS5uYW1lcyA9IHRvcF9tZXNlbmNoeW1hbF9nZW5lcyROYW1lLCBuZXcuc2hhcGVzID0gIlRSSUFOR0xFIikKYGBgCgpDaGFuZ2UgdGhlIHNpemUgb2YgdGhlIG5vZGUgdG8gYmUgY29ycmVsYXRlZCB3aXRoIHRoZSBNZXNlbmNoeW1hbCBwLXZhbHVlLiAKCmBgYHtyIGV2YWw9RkFMU0V9CnNldE5vZGVTaXplTWFwcGluZyh0YWJsZS5jb2x1bW4gPSAnTFIubWVzZW4nLCAKICAgICAgICAgICAgICAgICAgIHRhYmxlLmNvbHVtbi52YWx1ZXMgPSBjKG1pbihSTkFTZXFfZ2VuZV9zY29yZXMkTFIubWVzZW4pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW4oUk5BU2VxX2dlbmVfc2NvcmVzJExSLm1lc2VuKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgoUk5BU2VxX2dlbmVfc2NvcmVzJExSLm1lc2VuKSksIAogICAgICAgICAgICAgICAgICAgc2l6ZXMgPSBjKDMwLCA2MCwgMTUwKSxtYXBwaW5nLnR5cGUgPSAiYyIsIHN0eWxlLm5hbWUgPSBzdHlsZS5uYW1lKQpgYGAKCkdldCBhIHNjcmVlbnNob3Qgb2YgdGhlIHJlc3VsdGluZyBuZXR3b3JrCmBgYHtyIG1lc2VuX3N0cmluZ19uZXR3b3JrX3NjcmVlbnNob3QsIGluY2x1ZGU9VFJVRX0KbWVzZW5fc3RyaW5nX25ldHdvcmtfcG5nX2ZpbGVfbmFtZSA8LSBmaWxlLnBhdGgoZ2V0d2QoKSwiMjMwX0lzc2VybGluX1JDeTNfaW50cm8iLCAibWVzZW5fc3RyaW5nX25ldHdvcmsucG5nIikKYGBgCgpgYGB7ciBldmFsPUZBTFNFfQppZihmaWxlLmV4aXN0cyhtZXNlbl9zdHJpbmdfbmV0d29ya19wbmdfZmlsZV9uYW1lKSl7CiAgI2N5dG9zY2FwZSBoYW5ncyB3YWl0aW5nIGZvciB1c2VyIHJlc3BvbnNlIGlmIGZpbGUgYWxyZWFkeSBleGlzdHMuICBSZW1vdmUgaXQgZmlyc3QKICByZXNwb25zZTwtIGZpbGUucmVtb3ZlKG1lc2VuX3N0cmluZ19uZXR3b3JrX3BuZ19maWxlX25hbWUpCiAgfSAKcmVzcG9uc2UgPC0gZXhwb3J0SW1hZ2UobWVzZW5fc3RyaW5nX25ldHdvcmtfcG5nX2ZpbGVfbmFtZSwgdHlwZSA9ICJwbmciKQpgYGAKCmBgYHtyIG1lc2Vuc3RyaW5nbmV0d29yaywgZWNobz1GQUxTRSwgZmlnLmNhcD0iRm9ybWF0dGVkIFN0cmluZyBuZXR3b3JrIGZyb20gb3VyIHNldCBvZiBNZXNlbmNoeW1hbCBxdWVyeSBnZW5lcy4gIEFubm90YXRlZCB3aXRoIG91ciBleHByZXNzaW4gZGF0YSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKG1lc2VuX3N0cmluZ19uZXR3b3JrX3BuZ19maWxlX25hbWUpCmBgYAoKIyBVc2UgQ2FzZSAyIC0gV2hpY2ggZ2VuZXMgaGF2ZSBzaW1pbGFyIGV4cHJlc3Npb24uCgpJbnN0ZWFkIG9mIHF1ZXJ5aW5nIGV4aXN0aW5nIHJlc291cmNlcyBsb29rIGZvciBjb3JyZWxhdGlvbnMgaW4geW91ciBvd24gZGF0YXNldCB0byBmaW5kIG91dCB3aGljaCBnZW5lcyBoYXZlIHNpbWlsYXIgZXhwcmVzc2lvbi4gIFRoZXJlIGFyZSBtYW55IHRvb2xzIHRoYXQgY2FuIGFuYWx5emUgeW91ciBkYXRhIGZvciBjb3JyZWxhdGlvbi4gIEEgcG9wdWxhciB0b29sIGlzIFdlaWdodGVkIEdlbmUgQ29ycmVsYXRpb24gTmV0d29yayBBbmFseXNpcyAoV0dDTkEpW0B3Z2NuYV0gd2hpY2ggdGFrZXMgZXhwcmVzc2lvbiBkYXRhIGFuZCBjYWxjdWxhdGVzIGZ1bmN0aW9uYWwgbW9kdWxlcy4gIEFzIGEgc2ltcGxlIGV4YW1wbGUgd2UgY2FuIHRyYW5zZm9ybSBvdXIgZXhwcmVzc2lvbiBkYXRhc2V0IGludG8gYSBjb3JyZWxhdGlvbiBtYXRyaXguICAKClVzaW5nIHRoZSBDeXRvc2NhcGUgQXBwLCBhTWF0UmVhZGVyW0BhbWF0cmVhZGVyXSwgd2UgdHJhbnNmb3JtIG91ciBhZGphY2VuY3kgbWF0cml4IGludG8gYW4gaW50ZXJhY3Rpb24gbmV0d29yay4gRmlyc3Qgd2UgZmlsdGVyIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXggdG8gY29udGFpbiBvbmx5IHRoZSBzdHJvbmdlc3QgY29ubmVjdGlvbnMgKGZvciBleGFtcGxlLCBvbmx5IGNvcnJlbGF0aW9ucyBncmVhdGVyIHRoYW4gMC45KS4gCgpgYGB7cn0KClJOQVNlcV9leHByZXNzaW9uIDwtIFJOQVNlcV9leHByZXNzaW9uX21hdHJpeFssMzpuY29sKFJOQVNlcV9leHByZXNzaW9uX21hdHJpeCldCgpyb3duYW1lcyhSTkFTZXFfZXhwcmVzc2lvbikgPC0gUk5BU2VxX2V4cHJlc3Npb25fbWF0cml4JE5hbWUKUk5Bc2VxX2NvcnJlbGF0aW9uX21hdHJpeCA8LSBjb3IodChSTkFTZXFfZXhwcmVzc2lvbiksIG1ldGhvZD0icGVhcnNvbiIpCgojc2V0IHRoZSBkaWFnb25hbCBvZiBtYXRyaXggdG8gemVybyAtIGVsaW1pbmF0ZSBzZWxmLWNvcnJlbGF0aW9uClJOQXNlcV9jb3JyZWxhdGlvbl9tYXRyaXhbIAogIHJvdyhSTkFzZXFfY29ycmVsYXRpb25fbWF0cml4KSA9PSBjb2woUk5Bc2VxX2NvcnJlbGF0aW9uX21hdHJpeCkgXSA8LSAwCgojIHNldCBhbGwgY29ycmVsYXRpb25zIHRoYXQgYXJlIGxlc3MgdGhhbiAwLjkgdG8gemVybwpSTkFzZXFfY29ycmVsYXRpb25fbWF0cml4W3doaWNoKFJOQXNlcV9jb3JyZWxhdGlvbl9tYXRyaXg8MC45MCldIDwtIDAKCiNnZXQgcmlkIG9mIHJvd3MgYW5kIGNvbHVtbnMgdGhhdCBoYXZlIG5vIGNvcnJlbGF0aW9ucyB3aXRoIHRoZSBhYm92ZSB0aHJlc2hvbGRzClJOQXNlcV9jb3JyZWxhdGlvbl9tYXRyaXggPC0gUk5Bc2VxX2NvcnJlbGF0aW9uX21hdHJpeFt3aGljaChyb3dTdW1zKFJOQXNlcV9jb3JyZWxhdGlvbl9tYXRyaXgpICE9IDApLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoKGNvbFN1bXMoUk5Bc2VxX2NvcnJlbGF0aW9uX21hdHJpeCkgIT0wKV0KCiN3cml0ZSBvdXQgdGhlIGNvcnJlbGF0aW9uIGZpbGUKY29ycmVsYXRpb25fZmlsZW5hbWUgPC0gZmlsZS5wYXRoKGdldHdkKCksICIyMzBfSXNzZXJsaW5fUkN5M19pbnRybyIsICJUQ0dBX09WX1JOQXNlcV9leHByZXNzaW9uX2NvcnJlbGF0aW9uX21hdHJpeC50eHQiKSAKd3JpdGUudGFibGUoUk5Bc2VxX2NvcnJlbGF0aW9uX21hdHJpeCwgIGZpbGUgPSBjb3JyZWxhdGlvbl9maWxlbmFtZSwgY29sLm5hbWVzICA9IFRSVUUsIHJvdy5uYW1lcyA9IEZBTFNFLCBzZXAgPSAiXHQiLCBxdW90ZT1GQUxTRSkKCmBgYAoKVXNlIHRoZSBDeVJlc3QgY2FsbCB0byBhY2Nlc3MgdGhlIGFNYXRSZWFkZXIgZnVuY3Rpb25hbGl0eS4KCmBgYHtyIGV2YWw9RkFMU0V9CmFtYXRfdXJsIDwtICJhTWF0UmVhZGVyL3YxL2ltcG9ydCIKYW1hdF9wYXJhbXMgPSBsaXN0KGZpbGVzID0gbGlzdChjb3JyZWxhdGlvbl9maWxlbmFtZSksCiAgICAgICAgICAgICAgICAgICBkZWxpbWl0ZXIgPSAiVEFCIiwKICAgICAgICAgICAgICAgICAgIHVuZGlyZWN0ZWQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGlnbm9yZVplcm9zID0gVFJVRSwKICAgICAgICAgICAgICAgICAgIGludGVyYWN0aW9uTmFtZSA9ICJjb3JyZWxhdGVkIHdpdGgiLAogICAgICAgICAgICAgICAgICAgcm93TmFtZXMgPSBGQUxTRQogICAgICAgICAgICAgICAgICAgKQogCnJlc3BvbnNlIDwtIGN5cmVzdFBPU1Qob3BlcmF0aW9uID0gYW1hdF91cmwsIGJvZHkgPSBhbWF0X3BhcmFtcywgYmFzZS51cmwgPSAiaHR0cDovL2xvY2FsaG9zdDoxMjM0IikKCmN1cnJlbnRfbmV0d29ya19pZCA8LSByZXNwb25zZSRkYXRhWyJzdWlkIl0KYGBgCgoKYGBge3IgZXZhbD1GQUxTRX0KI3JlbGF5b3V0IG5ldHdvcmsKbGF5b3V0TmV0d29yaygnY29zZScsCiAgICAgICAgICAgICAgbmV0d29yayA9IGFzLm51bWVyaWMoY3VycmVudF9uZXR3b3JrX2lkKSkKYGBgCgoKYGBge3IgZXZhbD1GQUxTRX0KcmVuYW1lTmV0d29yayh0aXRsZSA9IkNvZXhwcmVzc2lvbl9uZXR3b3JrX3BlYXIwXzk1X25ldyIsCiAgICAgICAgICAgICAgbmV0d29yayA9IGFzLm51bWVyaWMoY3VycmVudF9uZXR3b3JrX2lkKSkKYGBgCgoKTW9kaWZ5IHRoZSB2aXN1YWxpemF0aW9uIHRvIHNlZSB3aGVyZSBlYWNoIGdlbmVzIGlzIHByZWRvbWluYW50bHkgZXhwcmVzc2VkLiAgTG9vayBhdCB0aGUgNCBkaWZmZXJlbnQgcC12YWx1ZXMgYXNzb2NpYXRlZCB3aXRoIGVhY2ggZ2VuZSBhbmQgY29sb3IgdGhlIG5vZGVzIHdpdGggdGhlIHR5cGUgYXNzb2NpYXRlZCB3aXRoIHRoZSBsb3dlc3QgRkRSLgoKTG9hZCBpbiB0aGUgc2NvcmluZyBkYXRhLiAgU3BlY2lmeSB0aGUgY2FuY2VyIHR5cGUgd2hlcmUgdGhlIGdlbmVzIGhhcyB0aGUgbG93ZXN0IEZEUiB2YWx1ZS4KCmBgYHtyfQpub2Rlc19pbl9uZXR3b3JrIDwtIHJvd25hbWVzKFJOQXNlcV9jb3JyZWxhdGlvbl9tYXRyaXgpCgojYWRkIGFuIGFkZGl0aW9uYWwgY29sdW1uIHRvIHRoZSBnZW5lIHNjb3JlcyB0YWJsZSB0byBpbmRpY2F0ZSBpbiB3aGljaCBzYW1wbGVzCiMgdGhlIGdlbmUgaXMgc2lnbmlmaWNhbnQKbm9kZV9jbGFzcyA8LSB2ZWN0b3IobGVuZ3RoID0gbGVuZ3RoKG5vZGVzX2luX25ldHdvcmspLG1vZGUgPSAiY2hhcmFjdGVyIikKZm9yKGkgaW4gMTpsZW5ndGgobm9kZXNfaW5fbmV0d29yaykpewogIGN1cnJlbnRfcm93IDwtIHdoaWNoKFJOQVNlcV9nZW5lX3Njb3JlcyROYW1lID09IG5vZGVzX2luX25ldHdvcmtbaV0pCiAgbWluX3B2YWx1ZSA8LSBtaW4oUk5BU2VxX2dlbmVfc2NvcmVzW2N1cnJlbnRfcm93LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwKGNvbG5hbWVzKFJOQVNlcV9nZW5lX3Njb3JlcyksIHBhdHRlcm4gPSAiRkRSIildKQogIGlmKFJOQVNlcV9nZW5lX3Njb3JlcyRGRFIubWVzZW5bY3VycmVudF9yb3ddIDw9bWluX3B2YWx1ZSl7CiAgICBub2RlX2NsYXNzW2ldIDwtIHBhc3RlKG5vZGVfY2xhc3NbaV0sIm1lc2VuIixzZXAgPSAiICIpCiAgfQogIGlmKFJOQVNlcV9nZW5lX3Njb3JlcyRGRFIuZGlmZltjdXJyZW50X3Jvd10gPD1taW5fcHZhbHVlKXsKICAgIG5vZGVfY2xhc3NbaV0gPC0gcGFzdGUobm9kZV9jbGFzc1tpXSwiZGlmZiIsc2VwID0gIiAiKQogIH0KICBpZihSTkFTZXFfZ2VuZV9zY29yZXMkRkRSLnByb2xpZltjdXJyZW50X3Jvd10gPD1taW5fcHZhbHVlKXsKICAgIG5vZGVfY2xhc3NbaV0gPC0gcGFzdGUobm9kZV9jbGFzc1tpXSwicHJvbGlmIixzZXAgPSAiICIpCiAgfQogIGlmKFJOQVNlcV9nZW5lX3Njb3JlcyRGRFIuaW1tdW5vW2N1cnJlbnRfcm93XSA8PW1pbl9wdmFsdWUpewogICAgbm9kZV9jbGFzc1tpXSA8LSBwYXN0ZShub2RlX2NsYXNzW2ldLCJpbW11bm8iLHNlcCA9ICIgIikKICB9Cn0Kbm9kZV9jbGFzcyA8LSB0cmltd3Mobm9kZV9jbGFzcykKbm9kZV9jbGFzc19kZiA8LWRhdGEuZnJhbWUobmFtZT1ub2Rlc19pbl9uZXR3b3JrLCBub2RlX2NsYXNzLHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCmhlYWQobm9kZV9jbGFzc19kZikKYGBgCgpNYXAgdGhlIG5ldyBub2RlIGF0dHJpYnV0ZSBhbmQgdGhlIGFsbCB0aGUgZ2VuZSBzY29yZXMgdG8gdGhlIG5ldHdvcmsuCmBgYHtyIGV2YWw9RkFMU0V9CmxvYWRUYWJsZURhdGEoUk5BU2VxX2dlbmVfc2NvcmVzLHRhYmxlLmtleS5jb2x1bW4gPSAibmFtZSIsZGF0YS5rZXkuY29sdW1uID0gIk5hbWUiKSAgI2RlZmF1bHQgZGF0YS5mcmFtZSBrZXkgaXMgcm93Lm5hbWVzCgpsb2FkVGFibGVEYXRhKG5vZGVfY2xhc3NfZGYsdGFibGUua2V5LmNvbHVtbiA9ICJuYW1lIixkYXRhLmtleS5jb2x1bW4gPSAibmFtZSIpICAjZGVmYXVsdCBkYXRhLmZyYW1lIGtleSBpcyByb3cubmFtZXMKYGBgCgpDcmVhdGUgYSBjb2xvciBtYXBwaW5nIGZvciB0aGUgZGlmZmVyZW50IGNhbmNlciB0eXBlcy4KCmBgYHtyIGV2YWw9RkFMU0V9CiNjcmVhdGUgYSBuZXcgbWFwcGluZyB3aXRoIHRoZSBkaWZmZXJlbnQgdHlwZXMKdW5pcXVlX3R5cGVzIDwtIHNvcnQodW5pcXVlKG5vZGVfY2xhc3MpKQoKY291bCA9IGJyZXdlci5wYWwoNCwgIlNldDEiKSAKIAojIEkgY2FuIGFkZCBtb3JlIHRvbmVzIHRvIHRoaXMgcGFsZXR0ZSA6CmNvdWwgPSBjb2xvclJhbXBQYWxldHRlKGNvdWwpKGxlbmd0aCh1bmlxdWVfdHlwZXMpKQoKc2V0Tm9kZUNvbG9yTWFwcGluZyh0YWJsZS5jb2x1bW4gPSAibm9kZV9jbGFzcyIsdGFibGUuY29sdW1uLnZhbHVlcyA9IHVuaXF1ZV90eXBlcywKICAgICAgICAgICAgICAgICAgICBjb2xvcnMgPSBjb3VsLG1hcHBpbmcudHlwZSA9ICJkIikKYGBgCgpgYGB7ciBjb3JyZWxhdGlvbm5ldHdvcmssIGluY2x1ZGU9VFJVRX0KY29ycmVsYXRpb25fbmV0d29ya19wbmdfZmlsZV9uYW1lIDwtIGZpbGUucGF0aChnZXR3ZCgpLCIyMzBfSXNzZXJsaW5fUkN5M19pbnRybyIsICJjb3JyZWxhdGlvbl9uZXR3b3JrLnBuZyIpCgpgYGAKCmBgYHtyIGV2YWw9RkFMU0V9CmlmKGZpbGUuZXhpc3RzKGNvcnJlbGF0aW9uX25ldHdvcmtfcG5nX2ZpbGVfbmFtZSkpewogICNjeXRvc2NhcGUgaGFuZ3Mgd2FpdGluZyBmb3IgdXNlciByZXNwb25zZSBpZiBmaWxlIGFscmVhZHkgZXhpc3RzLiAgUmVtb3ZlIGl0IGZpcnN0CiAgZmlsZS5yZW1vdmUoY29ycmVsYXRpb25fbmV0d29ya19wbmdfZmlsZV9uYW1lKQogIH0gCgojZXhwb3J0IHRoZSBuZXR3b3JrCmV4cG9ydEltYWdlKGNvcnJlbGF0aW9uX25ldHdvcmtfcG5nX2ZpbGVfbmFtZSwgdHlwZSA9ICJwbmciKQpgYGAKCmBgYHtyIGNvcnJlbGF0aW9uTmV0d29yazIsIGVjaG89RkFMU0UsIGZpZy5jYXA9IkV4YW1wbGUgY29ycmVsYXRpb24gbmV0d29yayBjcmVhdGVkIHVzaW5nIGFNYXRSZWFkZXIifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhjb3JyZWxhdGlvbl9uZXR3b3JrX3BuZ19maWxlX25hbWUpCmBgYAoKY2x1c3RlciB0aGUgTmV0d29yawpgYGB7ciBldmFsPUZBTFNFfQojbWFrZSBzdXJlIGl0IGlzIHNldCB0byB0aGUgcmlnaHQgbmV0d29yawogIHNldEN1cnJlbnROZXR3b3JrKG5ldHdvcmsgPSBnZXROZXR3b3JrTmFtZShzdWlkPWFzLm51bWVyaWMoY3VycmVudF9uZXR3b3JrX2lkKSkpCgogICNjbHVzdGVyIHRoZSBuZXR3b3JrCiAgY2x1c3Rlcm1ha2VyX3VybCA8LSBwYXN0ZSgiY2x1c3RlciBtY2wgbmV0d29yaz1TVUlEOiIsY3VycmVudF9uZXR3b3JrX2lkLCBzZXA9IiIpCiAgY29tbWFuZHNHRVQoY2x1c3Rlcm1ha2VyX3VybCkKICAKICAjZ2V0IHRoZSBjbHVzdGVyaW5nIHJlc3VsdHMKICBkZWZhdWx0X25vZGVfdGFibGUgPC0gZ2V0VGFibGVDb2x1bW5zKHRhYmxlPSAibm9kZSIsbmV0d29yayA9IGFzLm51bWVyaWMoY3VycmVudF9uZXR3b3JrX2lkKSkKIAogIGhlYWQoZGVmYXVsdF9ub2RlX3RhYmxlKQpgYGAKClBlcmZvcm0gcGF0aHdheSBFbnJpY2htZW50IG9uIG9uZSBvZiB0aGUgY2x1c3RlcnMgdXNpbmcgZzpQcm9maWxlcltAZ3Byb2ZpbGVyXS4gZzpQcm9maWxlciBpcyBhbiBvbmxpbmUgZnVuY3Rpb25hbCBlbnJpY2htZW50IHdlYiBzZXJ2aWNlIHRoYXQgd2lsbCB0YWtlIHlvdXIgZ2VuZSBsaXN0IGFuZCByZXR1cm4gdGhlIHNldCBvZiBlbnJpY2hlZCBwYXRod2F5cy4gIEZvciBhdXRvbWF0ZWQgYW5hbHlzaXMgZzpQcm9maWxlciBoYXMgY3JlYXRlZCBhbiBSIGxpYnJhcnkgdG8gaW50ZXJhY3Qgd2l0aCBpdCBkaXJlY3RseSBmcm9tIFIgaW5zdGVhZCBvZiB1c2luZyB0aGUgd2ViIHBhZ2UuIAoKQ3JlYXRlIGEgZnVuY3Rpb24gdG8gY2FsbCBnOlByb2ZpbGVyIGFuZCBjb252ZXJ0IHRoZSByZXR1cm5lZCByZXN1bHRzIGludG8gYSBnZW5lcmljIGVucmljaG1lbnQgbWFwIGlucHV0IGZpbGUuCmBgYHtyfQp0cnlDYXRjaChleHByID0geyBsaWJyYXJ5KCJnUHJvZmlsZVIiKX0sIAogICAgICAgICBlcnJvciA9IGZ1bmN0aW9uKGUpIHsgaW5zdGFsbC5wYWNrYWdlcygiZ1Byb2ZpbGVSIil9LCBmaW5hbGx5ID0gbGlicmFyeSgiZ1Byb2ZpbGVSIikpCgojZnVuY3Rpb24gdG8gcnVuIGdwcm9maWxlciB1c2luZyB0aGUgZ3Byb2ZpbGVyIGxpYnJhcnkKIyAKIyBUaGUgZnVuY3Rpb24gdGFrZXMgdGhlIHJldHVybmVkIGdwcm9maWxlciByZXN1bHRzIGFuZCBmb3JtYXRzIGl0IHRvIHRoZSBnZW5lcmljIEVNIGlucHV0IGZpbGUKIwojIGZ1bmN0aW9uIHJldHVybnMgYSBkYXRhIGZyYW1lIGluIHRoZSBnZW5lcmljIEVNIGZpbGUgZm9ybWF0LgpydW5HcHJvZmlsZXIgPC0gZnVuY3Rpb24oZ2VuZXMsY3VycmVudF9vcmdhbmlzbSA9ICJoc2FwaWVucyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgc2lnbmlmaWNhbnRfb25seSA9IEYsIHNldF9zaXplX21heCA9IDIwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXRfc2l6ZV9taW4gPSAzLCBmaWx0ZXJfZ3Nfc2l6ZV9taW4gPSA1ICwgZXhjbHVkZV9pZWEgPSBGKXsKICAKICBncHJvZmlsZXJfcmVzdWx0cyA8LSBncHJvZmlsZXIoZ2VuZXMgLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWduaWZpY2FudD1zaWduaWZpY2FudF9vbmx5LG9yZGVyZWRfcXVlcnkgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2x1ZGVfaWVhPWV4Y2x1ZGVfaWVhLG1heF9zZXRfc2l6ZSA9IHNldF9zaXplX21heCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluX3NldF9zaXplID0gc2V0X3NpemVfbWluLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JyZWN0aW9uX21ldGhvZCA9ICJmZHIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9IGN1cnJlbnRfb3JnYW5pc20sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3JjX2ZpbHRlciA9IGMoIkdPOkJQIiwiUkVBQyIpKQogIAogICNmaWx0ZXIgcmVzdWx0cwogIGdwcm9maWxlcl9yZXN1bHRzIDwtIGdwcm9maWxlcl9yZXN1bHRzW3doaWNoKGdwcm9maWxlcl9yZXN1bHRzWywndGVybS5zaXplJ10gPj0gMwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiBncHJvZmlsZXJfcmVzdWx0c1ssJ292ZXJsYXAuc2l6ZSddID49IGZpbHRlcl9nc19zaXplX21pbiApLF0KICAKICAjIGdQcm9maWxlUiByZXR1cm5zIGNvcnJlY3RlZCBwLXZhbHVlcyBvbmx5LiAgU2V0IHAtdmFsdWUgdG8gY29ycmVjdGVkIHAtdmFsdWUKICBpZihkaW0oZ3Byb2ZpbGVyX3Jlc3VsdHMpWzFdID4gMCl7CiAgICBlbV9yZXN1bHRzIDwtIGNiaW5kKGdwcm9maWxlcl9yZXN1bHRzWywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJ0ZXJtLmlkIiwidGVybS5uYW1lIiwicC52YWx1ZSIsInAudmFsdWUiKV0sIDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3Byb2ZpbGVyX3Jlc3VsdHNbLCJpbnRlcnNlY3Rpb24iXSkKICBjb2xuYW1lcyhlbV9yZXN1bHRzKSA8LSBjKCJOYW1lIiwiRGVzY3JpcHRpb24iLCAicHZhbHVlIiwicXZhbHVlIiwicGhlbm90eXBlIiwiZ2VuZXMiKQogIAogIHJldHVybihlbV9yZXN1bHRzKQogIH0gZWxzZSB7CiAgICByZXR1cm4oIm5vIGdwcm9maWxlciByZXN1bHRzIGZvciBzdXBwbGllZCBxdWVyeSIpCiAgfQp9CmBgYAoKUnVuIGc6UHJvZmlsZXIuICBnOlByb2ZpbGVyIHdpbGwgcmV0dXJuIGEgc2V0IG9mIHBhdGh3YXlzIGFuZCBmdW5jdGlvbnMgdGhhdCBhcmUgZm91bmQgdG8gYmUgZW5yaWNoZWQgaW4gb3VyIHF1ZXJ5IHNldCBvZiBnZW5lcy4gIAoKYGBge3IgZXZhbD1GQUxTRX0KICBjdXJyZW50X2NsdXN0ZXIgPC0gIjEiCiAgI3NlbGVjdCBhbGwgdGhlIG5vZGVzIGluIGNsdXN0ZXIgMQogIHNlbGVjdGVkbm9kZXMgPC0gc2VsZWN0Tm9kZXMoY3VycmVudF9jbHVzdGVyLCBieS5jb2w9Il9fbWNsQ2x1c3RlciIpCiAgCiAgI2NyZWF0ZSBhIHN1Ym5ldHdvcmsgd2l0aCBjbHVzdGVyIDEKICBzdWJuZXR3b3JrX3N1aWQgPC0gY3JlYXRlU3VibmV0d29yayhub2Rlcz0ic2VsZWN0ZWQiKQogIAogIHJlbmFtZU5ldHdvcmsoIkNsdXN0ZXIxX1N1Ym5ldHdvcmsiLCBuZXR3b3JrPWFzLm51bWVyaWMoc3VibmV0d29ya19zdWlkKSkKICAKICBzdWJuZXR3b3JrX25vZGVfdGFibGUgPC0gZ2V0VGFibGVDb2x1bW5zKHRhYmxlPSAibm9kZSIsbmV0d29yayA9IGFzLm51bWVyaWMoc3VibmV0d29ya19zdWlkKSkKCiAgZW1fcmVzdWx0cyA8LSBydW5HcHJvZmlsZXIoc3VibmV0d29ya19ub2RlX3RhYmxlJG5hbWUpCiAgCiAjd3JpdGUgb3V0IHRoZSBnOlByb2ZpbGVyIHJlc3VsdHMKIGVtX3Jlc3VsdHNfZmlsZW5hbWUgPC1maWxlLnBhdGgoZ2V0d2QoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMzBfSXNzZXJsaW5fUkN5M19pbnRybyIscGFzdGUoImdwcm9maWxlcl9jbHVzdGVyIixjdXJyZW50X2NsdXN0ZXIsImVucl9yZXN1bHRzLnR4dCIsc2VwPSJfIikpCgogIHdyaXRlLnRhYmxlKGVtX3Jlc3VsdHMsZW1fcmVzdWx0c19maWxlbmFtZSxjb2wubmFtZT1UUlVFLHNlcD0iXHQiLHJvdy5uYW1lcz1GQUxTRSxxdW90ZT1GQUxTRSkKICAKIAogIGhlYWQoZW1fcmVzdWx0cykKYGBgCgpDcmVhdGUgYW4gZW5yaWNobWVudCBtYXAgd2l0aCB0aGUgcmV0dXJuZWQgZzpQcm9maWxlciByZXN1bHRzLiAgQW4gZW5yaWNobWVudCBtYXAgaXMgYSBkaWZmZXJlbnQgc29ydCBvZiBuZXR3b3JrLiAgSW5zdGVhZCBvZiBub2RlcyByZXByZXNlbnRpbmcgZ2VuZXMsIG5vZGVzIHJlcHJlc2VudCBwYXRod2F5cyBvciBmdW5jdGlvbnMuICBFZGdlcyBiZXR3ZWVuIHRoZXNlIHBhdGh3YXlzIG9yIGZ1bmN0aW9ucyByZXByZXNlbnQgc2hhcmVkIGdlbmVzIG9yIHBhdGh3YXkgY3Jvc3N0YWxrLiAgQW4gZW5yaWNobWVudCBtYXAgaXMgYSB3YXkgdG8gdmlzdWFsaXplIHlvdXIgZW5yaWNobWVudCByZXN1bHRzIHRvIGhlbHAgcmVkdWNlIHJlZHVuZGFuY3kgYW5kIHVuY292ZXIgbWFpbiB0aGVtZXMuICBQYXRod2F5cyBjYW4gYWxzbyBiZSBleHBsb3JlZCBpbiBkZXRhaWwgdXNpbmcgdGhlIGZlYXR1cmVzIGF2YWlsYWJsZSB0aHJvdWdoIHRoZSBBcHAgaW4gQ3l0b3NjYXBlLiAKYGBge3IgZXZhbD1GQUxTRX0KIGVtX2NvbW1hbmQgPSBwYXN0ZSgnZW5yaWNobWVudG1hcCBidWlsZCBhbmFseXNpc1R5cGU9ImdlbmVyaWMiICcsIAogICAgICAgICAgICAgICAgICAgJ3B2YWx1ZT0nLCIwLjA1IiwgJ3F2YWx1ZT0nLCIwLjA1IiwKICAgICAgICAgICAgICAgICAgICdzaW1pbGFyaXR5Y3V0b2ZmPScsIjAuMjUiLAogICAgICAgICAgICAgICAgICAgJ2NvZWZmZWNpZW50cz0nLCJKQUNDQVJEIiwKICAgICAgICAgICAgICAgICAgICdlbnJpY2htZW50c0RhdGFzZXQxPScsZW1fcmVzdWx0c19maWxlbmFtZSAsCiAgICAgICAgICAgICAgICAgICBzZXA9IiAiKQoKICAjZW5yaWNobWVudCBtYXAgY29tbWFuZCB3aWxsIHJldHVybiB0aGUgc3VpZCBvZiBuZXdseSBjcmVhdGVkIG5ldHdvcmsuCiAgZW1fbmV0d29ya19zdWlkIDwtIGNvbW1hbmRzUnVuKGVtX2NvbW1hbmQpCiAgCiAgcmVuYW1lTmV0d29yaygiQ2x1c3RlcjFfZW5yaWNobWVudG1hcCIsIG5ldHdvcms9YXMubnVtZXJpYyhlbV9uZXR3b3JrX3N1aWQpKQpgYGAKCkV4cG9ydCBpbWFnZSBvZiByZXN1bHRpbmcgRW5yaWNobWVudCBtYXAuCgpgYGB7ciBjbHVzdGVyMWVtLCBpbmNsdWRlPVRSVUV9CmNsdXN0ZXIxZW1fcG5nX2ZpbGVfbmFtZSA8LSBmaWxlLnBhdGgoZ2V0d2QoKSwiMjMwX0lzc2VybGluX1JDeTNfaW50cm8iLCJjbHVzdGVyMWVtLnBuZyIpCgpgYGAKCmBgYHtyIGV2YWw9RkFMU0V9CmlmKGZpbGUuZXhpc3RzKGNsdXN0ZXIxZW1fcG5nX2ZpbGVfbmFtZSkpewogICNjeXRvc2NhcGUgaGFuZ3Mgd2FpdGluZyBmb3IgdXNlciByZXNwb25zZSBpZiBmaWxlIGFscmVhZHkgZXhpc3RzLiAgUmVtb3ZlIGl0IGZpcnN0CiAgZmlsZS5yZW1vdmUoY2x1c3RlcjFlbV9wbmdfZmlsZV9uYW1lKQogIH0gCgojZXhwb3J0IHRoZSBuZXR3b3JrCmV4cG9ydEltYWdlKGNsdXN0ZXIxZW1fcG5nX2ZpbGVfbmFtZSwgdHlwZSA9ICJwbmciKQpgYGAKCmBgYHtyIGNsdXN0ZXIxZW1maWcsIGVjaG89RkFMU0UsIGZpZy5jYXA9IkV4YW1wbGUgRW5yaWNobWVudCBNYXAgY3JlYXRlZCB3aGVuIHJ1bm5pbmcgYW4gZW5yaWNobWVudCBhbmFseXNpcyB1c2luZyBnOlByb2ZpbGVyIHdpdGggdGhlIGdlbmVzIHRoYXQgYXJlIHBhcnQgb2YgY2x1c3RlciAxIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoY2x1c3RlcjFlbV9wbmdfZmlsZV9uYW1lKQpgYGAKCkFubm90YXRlIHRoZSBFbnJpY2htZW50IG1hcCB0byBnZXQgdGhlIGdlbmVyYWwgdGhlbWVzIHRoYXQgYXJlIGZvdW5kIGluIHRoZSBlbnJpY2htZW50IHJlc3VsdHMgb2YgY2x1c3RlciAxCmBgYHtyIGV2YWw9RkFMU0V9CgojZ2V0IHRoZSBjb2x1bW4gZnJvbSB0aGUgbm9kZXRhYmxlIGFuZCBub2RlIHRhYmxlCiAgbm9kZXRhYmxlX2NvbG5hbWVzIDwtIGdldFRhYmxlQ29sdW1uTmFtZXModGFibGU9Im5vZGUiLCAgbmV0d29yayA9ICBhcy5udW1lcmljKGVtX25ldHdvcmtfc3VpZCkpCgogIGRlc2NyX2F0dHJpYiA8LSBub2RldGFibGVfY29sbmFtZXNbZ3JlcChub2RldGFibGVfY29sbmFtZXMsIHBhdHRlcm4gPSAiR1NfREVTQ1IiKV0KCiAgI0F1dG9hbm5vdGF0ZSB0aGUgbmV0d29yawogIGF1dG9hbm5vdGF0ZV91cmwgPC0gcGFzdGUoImF1dG9hbm5vdGF0ZSBhbm5vdGF0ZS1jbHVzdGVyQm9vc3RlZCBsYWJlbENvbHVtbj0iLCBkZXNjcl9hdHRyaWIsIiBtYXhXb3Jkcz0zICIsIHNlcD0iIikKICAgIGN1cnJlbnRfbmFtZSA8LWNvbW1hbmRzR0VUKGF1dG9hbm5vdGF0ZV91cmwpCgpgYGAKCkV4cG9ydCBpbWFnZSBvZiByZXN1bHRpbmcgQW5ub3RhdGVkIEVucmljaG1lbnQgbWFwLgoKYGBge3IgY2x1c3RlcjFlbWFubm90LCBpbmNsdWRlPVRSVUV9CmNsdXN0ZXIxZW1fYW5ub3RfcG5nX2ZpbGVfbmFtZSA8LSBmaWxlLnBhdGgoZ2V0d2QoKSwgIjIzMF9Jc3Nlcmxpbl9SQ3kzX2ludHJvIiwiY2x1c3RlcjFlbV9hbm5vdC5wbmciKQpgYGAKCmBgYHtyIGV2YWw9RkFMU0V9CmlmKGZpbGUuZXhpc3RzKGNsdXN0ZXIxZW1fYW5ub3RfcG5nX2ZpbGVfbmFtZSkpewogICNjeXRvc2NhcGUgaGFuZ3Mgd2FpdGluZyBmb3IgdXNlciByZXNwb25zZSBpZiBmaWxlIGFscmVhZHkgZXhpc3RzLiAgUmVtb3ZlIGl0IGZpcnN0CiAgZmlsZS5yZW1vdmUoY2x1c3RlcjFlbV9hbm5vdF9wbmdfZmlsZV9uYW1lKQogIH0gCgojZXhwb3J0IHRoZSBuZXR3b3JrCmV4cG9ydEltYWdlKGNsdXN0ZXIxZW1fYW5ub3RfcG5nX2ZpbGVfbmFtZSwgdHlwZSA9ICJwbmciKQpgYGAKCmBgYHtyIGNsdXN0ZXIxZW1hbm5vdGZpZywgZWNobz1GQUxTRSwgZmlnLmNhcD0iRXhhbXBsZSBBbm5vdGF0ZWQgRW5yaWNobWVudCBNYXAgY3JlYXRlZCB3aGVuIHJ1bm5pbmcgYW4gZW5yaWNobWVudCBhbmFseXNpcyB1c2luZyBnOlByb2ZpbGVyIHdpdGggdGhlIGdlbmVzIHRoYXQgYXJlIHBhcnQgb2YgY2x1c3RlciAxIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoY2x1c3RlcjFlbV9hbm5vdF9wbmdfZmlsZV9uYW1lKQpgYGAKCkRlbnNlIG5ldHdvcmtzIHNtYWxsIG9yIGxhcmdlIG5ldmVyIGxvb2sgbGlrZSBuZXR3b3JrIGZpZ3VyZXMgd2Ugc28gb2Z0ZW4gc2VlIGluIGpvdXJuYWxzLiAgQSBsb3Qgb2YgbWFudWFsIHR3ZWFraW5nLCByZW9yZ2FuaXphdGlvbiBhbmQgb3B0aW1pemF0aW9uIGlzIGludm9sdmVkIGluIGdldHRpbmcgdGhhdCBwZXJmZWN0IGZpZ3VyZSByZWFkeSBuZXR3b3JrLiAgVGhlIGFib3ZlIG5ldHdvcmsgaXMgd2hhdCB0aGUgbmV0d29yayBzdGFydHMgYXMuICBUaGUgYmVsb3cgZmlndXJlIGlzIHdoYXQgaXQgY2FuIGxvb2sgbGlrZSBhZnRlciBhIGZldyBtaW51dGVzIG9mIG1hbnVhbCByZW9yZ2FuaWF6YXRpb24uICAoaW5kaXZpZHVhbCBjbHVzdGVycyB3ZXJlIHNlbGVjdGVkIGZyb20gdGhlIGF1dG8gYW5ub3RhdGUgcGFuZWwgYW5kIHNlcGFyYXRlZCBmcm9tIG90aGVyIGNsdXN0ZXJzKQoKPGNlbnRlcj4KIVtdKGh0dHBzOi8vY3l0b3NjYXBlLmdpdGh1Yi5pby9jeXRvc2NhcGUtYXV0b21hdGlvbi9mb3Itc2NyaXB0ZXJzL1Ivbm90ZWJvb2tzL2Jpb2MyMDE4X1JjeTNfaW50cm8vMjMwX0lzc2VybGluX1JDeTNfaW50cm8vaW1hZ2VzL2NsdXN0ZXIxZW1fYW5ub3RfbWFuLnBuZykKPC9jZW50ZXI+